about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--Cargo.lock357
-rw-r--r--Cargo.toml37
-rw-r--r--REUSE.toml2
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs1
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs42
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs35
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs6
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl3
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs54
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml13
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/audit.yml1
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml1
-rw-r--r--compiler/rustc_codegen_cranelift/.zed/settings.json68
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock66
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml12
-rw-r--r--compiler/rustc_codegen_cranelift/Readme.md1
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs28
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/prepare.rs30
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/config.txt1
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/example/raw-dylib.rs31
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch32
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch75
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch6
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch14
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch25
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch47
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch37
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain3
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh8
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs84
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs27
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/compiler_builtins.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs144
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs18
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs6
-rw-r--r--compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock2
-rw-r--r--compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml4
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/archive.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl10
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs173
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs66
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs23
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs296
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs4
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs135
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs207
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs75
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs22
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs38
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs6
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs19
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs (renamed from compiler/rustc_const_eval/src/interpret/terminator.rs)812
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs763
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/mod.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs37
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs651
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs286
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs178
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs12
-rw-r--r--compiler/rustc_data_structures/src/steal.rs9
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs37
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0517.md19
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs25
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs1
-rw-r--r--compiler/rustc_errors/src/emitter.rs126
-rw-r--r--compiler/rustc_errors/src/json.rs9
-rw-r--r--compiler/rustc_errors/src/json/tests.rs3
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs51
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs5
-rw-r--r--compiler/rustc_feature/src/accepted.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs8
-rw-r--r--compiler/rustc_feature/src/removed.rs3
-rw-r--r--compiler/rustc_feature/src/unstable.rs9
-rw-r--r--compiler/rustc_hir/src/hir.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs40
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs66
-rw-r--r--compiler/rustc_hir_analysis/src/delegation.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs67
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs49
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs66
-rw-r--r--compiler/rustc_interface/src/passes.rs13
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_lint/messages.ftl8
-rw-r--r--compiler/rustc_lint/src/builtin.rs21
-rw-r--r--compiler/rustc_lint/src/context.rs18
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs3
-rw-r--r--compiler/rustc_lint/src/early.rs2
-rw-r--r--compiler/rustc_lint/src/let_underscore.rs11
-rw-r--r--compiler/rustc_lint/src/lib.rs7
-rw-r--r--compiler/rustc_lint/src/lints.rs12
-rw-r--r--compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs4
-rw-r--r--compiler/rustc_lint/src/types.rs22
-rw-r--r--compiler/rustc_lint/src/unused.rs7
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs71
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs9
-rw-r--r--compiler/rustc_llvm/build.rs29
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs31
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/lint.rs8
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs11
-rw-r--r--compiler/rustc_middle/src/query/mod.rs10
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs9
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs12
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs22
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs13
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs6
-rw-r--r--compiler/rustc_mir_transform/Cargo.toml1
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs8
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs146
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs74
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs13
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs131
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs75
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs73
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs7
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs39
-rw-r--r--compiler/rustc_passes/messages.ftl4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs210
-rw-r--r--compiler/rustc_passes/src/dead.rs214
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs1
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs7
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs19
-rw-r--r--compiler/rustc_pattern_analysis/tests/common/mod.rs4
-rw-r--r--compiler/rustc_query_system/src/query/job.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs10
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs23
-rw-r--r--compiler/rustc_resolve/src/ident.rs70
-rw-r--r--compiler/rustc_resolve/src/imports.rs54
-rw-r--r--compiler/rustc_resolve/src/late.rs204
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs1
-rw-r--r--compiler/rustc_resolve/src/lib.rs8
-rw-r--r--compiler/rustc_resolve/src/macros.rs30
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs5
-rw-r--r--compiler/rustc_session/src/config.rs53
-rw-r--r--compiler/rustc_session/src/config/cfg.rs65
-rw-r--r--compiler/rustc_session/src/filesearch.rs5
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs12
-rw-r--r--compiler/rustc_session/src/session.rs30
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/lib.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_target/src/target_features.rs560
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs70
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs169
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs25
-rw-r--r--compiler/rustc_transmute/src/layout/nfa.rs1
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs2
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs9
-rw-r--r--compiler/rustc_type_ir/src/fold.rs2
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs2
-rw-r--r--config.example.toml6
-rw-r--r--library/Cargo.lock (renamed from compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml)160
-rw-r--r--library/Cargo.toml44
-rw-r--r--library/alloc/Cargo.toml5
-rw-r--r--library/alloc/src/boxed.rs7
-rw-r--r--library/alloc/src/collections/binary_heap/mod.rs14
-rw-r--r--library/alloc/src/collections/btree/map.rs28
-rw-r--r--library/alloc/src/collections/btree/set.rs583
-rw-r--r--library/alloc/src/collections/vec_deque/into_iter.rs2
-rw-r--r--library/alloc/src/collections/vec_deque/iter.rs14
-rw-r--r--library/alloc/src/collections/vec_deque/iter_mut.rs14
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/rc.rs12
-rw-r--r--library/alloc/src/slice.rs96
-rw-r--r--library/alloc/src/string.rs2
-rw-r--r--library/alloc/src/sync.rs8
-rw-r--r--library/alloc/src/vec/mod.rs2
-rw-r--r--library/alloc/tests/arc.rs14
-rw-r--r--library/alloc/tests/boxed.rs37
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/alloc/tests/rc.rs17
-rw-r--r--library/core/src/arch.rs9
-rw-r--r--library/core/src/cell.rs19
-rw-r--r--library/core/src/default.rs1
-rw-r--r--library/core/src/intrinsics.rs289
-rw-r--r--library/core/src/intrinsics/mir.rs8
-rw-r--r--library/core/src/iter/sources/repeat_n.rs33
-rw-r--r--library/core/src/lib.rs6
-rw-r--r--library/core/src/num/f128.rs176
-rw-r--r--library/core/src/num/f16.rs171
-rw-r--r--library/core/src/num/f32.rs9
-rw-r--r--library/core/src/num/f64.rs9
-rw-r--r--library/core/src/num/flt2dec/strategy/dragon.rs49
-rw-r--r--library/core/src/pat.rs2
-rw-r--r--library/core/src/pin.rs50
-rw-r--r--library/core/src/primitive_docs.rs3
-rw-r--r--library/core/src/ptr/non_null.rs17
-rw-r--r--library/core/src/ptr/unique.rs4
-rw-r--r--library/core/src/slice/mod.rs100
-rw-r--r--library/core/src/slice/sort/shared/smallsort.rs22
-rw-r--r--library/core/src/slice/sort/unstable/mod.rs2
-rw-r--r--library/core/src/time.rs10
-rw-r--r--library/core/tests/pin.rs46
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/build.rs46
-rw-r--r--library/std/src/f128.rs1300
-rw-r--r--library/std/src/f128/tests.rs478
-rw-r--r--library/std/src/f16.rs1296
-rw-r--r--library/std/src/f16/tests.rs472
-rw-r--r--library/std/src/io/buffered/bufreader.rs34
-rw-r--r--library/std/src/io/buffered/bufreader/buffer.rs21
-rw-r--r--library/std/src/keyword_docs.rs2
-rw-r--r--library/std/src/lib.rs11
-rw-r--r--library/std/src/macros.rs2
-rw-r--r--library/std/src/os/fd/raw.rs1
-rw-r--r--library/std/src/os/solid/io.rs1
-rw-r--r--library/std/src/os/vxworks/mod.rs1
-rw-r--r--library/std/src/os/windows/io/raw.rs2
-rw-r--r--library/std/src/panic.rs29
-rw-r--r--library/std/src/sync/rwlock/tests.rs4
-rw-r--r--library/std/src/sys/cmath.rs15
-rw-r--r--library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs4
-rw-r--r--library/std/src/sys/pal/sgx/thread.rs1
-rw-r--r--library/std/src/sys/pal/uefi/time.rs8
-rw-r--r--library/std/src/sys/pal/unix/kernel_copy.rs25
-rw-r--r--library/std/src/sys/pal/unix/pipe.rs4
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix/tests.rs13
-rw-r--r--library/std/src/sys/pal/unix/process/process_vxworks.rs1
-rw-r--r--library/std/src/sys/pal/unix/thread.rs35
-rw-r--r--library/std/src/sys/pal/windows/net.rs1
-rw-r--r--library/std/src/sys/pal/windows/process.rs2
-rw-r--r--library/std/src/sys/pal/windows/stdio.rs4
m---------library/stdarch0
-rw-r--r--src/bootstrap/download-ci-llvm-stamp2
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs39
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs12
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/vendor.rs1
-rw-r--r--src/bootstrap/src/core/config/config.rs37
-rw-r--r--src/bootstrap/src/core/metadata.rs7
-rw-r--r--src/bootstrap/src/core/sanity.rs12
-rw-r--r--src/bootstrap/src/lib.rs19
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/helpers.rs3
-rw-r--r--src/bootstrap/src/utils/tarball.rs6
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile14
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile5
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile2
-rwxr-xr-xsrc/ci/docker/scripts/fuchsia-test-runner.py13
-rwxr-xr-xsrc/ci/docker/scripts/zstd.sh29
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/command-line-arguments.md4
-rw-r--r--src/doc/rustc/src/platform-support.md14
-rw-r--r--src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md47
-rw-r--r--src/doc/rustc/src/platform-support/vxworks.md8
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/inline.rs16
-rw-r--r--src/librustdoc/clean/mod.rs11
-rw-r--r--src/librustdoc/clean/simplify.rs1
-rw-r--r--src/librustdoc/clean/types.rs61
-rw-r--r--src/librustdoc/clean/utils.rs2
-rw-r--r--src/librustdoc/config.rs5
-rw-r--r--src/librustdoc/core.rs9
-rw-r--r--src/librustdoc/doctest.rs4
-rw-r--r--src/librustdoc/formats/cache.rs342
-rw-r--r--src/librustdoc/html/format.rs35
-rw-r--r--src/librustdoc/html/markdown.rs20
-rw-r--r--src/librustdoc/html/markdown/tests.rs6
-rw-r--r--src/librustdoc/html/render/mod.rs52
-rw-r--r--src/librustdoc/html/render/search_index.rs483
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css2
-rw-r--r--src/librustdoc/html/static/js/main.js26
-rw-r--r--src/librustdoc/json/conversions.rs4
-rw-r--r--src/librustdoc/json/mod.rs6
-rw-r--r--src/librustdoc/passes/stripper.rs9
-rw-r--r--src/rustdoc-json-types/lib.rs2
-rw-r--r--src/tools/build-manifest/src/main.rs1
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.cargo/config.toml7
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml13
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml17
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml5
-rw-r--r--src/tools/clippy/.github/workflows/lintcheck.yml4
-rw-r--r--src/tools/clippy/CHANGELOG.md2
-rw-r--r--src/tools/clippy/Cargo.toml3
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md6
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml4
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs724
-rw-r--r--src/tools/clippy/clippy_config/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_config/src/metadata.rs105
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs392
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs5
-rw-r--r--src/tools/clippy/clippy_dev/src/serve.rs15
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs324
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/as_conversions.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/asm_syntax.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs394
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/else_if_without_else.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_drop.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs327
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/if_not_else.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/incompatible_msrv.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.deprecated.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs77
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rotate.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs394
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_empty.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/repeat_once.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/bit_mask.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/erasing_op.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/identity_op.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/integer_division.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/partial_pub_fields.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/pub_use.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_patterns.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_buffer.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_mutex.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_result_ok.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs85
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/visibility.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs7
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs279
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs47
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs129
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs98
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml3
-rw-r--r--src/tools/clippy/declare_clippy_lint/src/lib.rs1
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml3
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs8
-rw-r--r--src/tools/clippy/lintcheck/src/input.rs6
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs28
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/rustc_tools_util/Cargo.toml3
-rw-r--r--src/tools/clippy/rustc_tools_util/src/lib.rs59
-rw-r--r--src/tools/clippy/src/driver.rs2
-rw-r--r--src/tools/clippy/src/main.rs1
-rw-r--r--src/tools/clippy/tests/check-fmt.rs1
-rw-r--r--src/tools/clippy/tests/compile-test.rs6
-rw-r--r--src/tools/clippy/tests/dogfood.rs1
-rw-r--r--src/tools/clippy/tests/integration.rs1
-rw-r--r--src/tools/clippy/tests/lint_message_convention.rs1
-rw-r--r--src/tools/clippy/tests/missing-test-files.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs30
-rw-r--r--src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr22
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs20
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr74
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr134
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.fixed68
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.rs68
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.stderr86
-rw-r--r--src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr10
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3717.stderr11
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6254.rs3
-rw-r--r--src/tools/clippy/tests/ui/create_dir.stderr13
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr4
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr2
-rw-r--r--src/tools/clippy/tests/ui/deprecated.rs31
-rw-r--r--src/tools/clippy/tests/ui/deprecated.stderr68
-rw-r--r--src/tools/clippy/tests/ui/deprecated_old.rs9
-rw-r--r--src/tools/clippy/tests/ui/deprecated_old.stderr23
-rw-r--r--src/tools/clippy/tests/ui/deref_by_slicing.fixed4
-rw-r--r--src/tools/clippy/tests/ui/deref_by_slicing.rs4
-rw-r--r--src/tools/clippy/tests/ui/deref_by_slicing.stderr8
-rw-r--r--src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs10
-rw-r--r--src/tools/clippy/tests/ui/empty_drop.stderr7
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed17
-rw-r--r--src/tools/clippy/tests/ui/eta.rs17
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr74
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.stderr111
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs13
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr118
-rw-r--r--src/tools/clippy/tests/ui/for_kv_map.fixed10
-rw-r--r--src/tools/clippy/tests/ui/for_kv_map.rs10
-rw-r--r--src/tools/clippy/tests/ui/for_kv_map.stderr13
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.stderr152
-rw-r--r--src/tools/clippy/tests/ui/if_let_mutex.rs9
-rw-r--r--src/tools/clippy/tests/ui/if_let_mutex.stderr24
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.fixed119
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.rs2
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.stderr19
-rw-r--r--src/tools/clippy/tests/ui/implicit_hasher.fixed102
-rw-r--r--src/tools/clippy/tests/ui/implicit_hasher.rs9
-rw-r--r--src/tools/clippy/tests/ui/implicit_hasher.stderr131
-rw-r--r--src/tools/clippy/tests/ui/implicit_return.stderr104
-rw-r--r--src/tools/clippy/tests/ui/lossy_float_literal.stderr76
-rw-r--r--src/tools/clippy/tests/ui/missing_trait_methods.rs8
-rw-r--r--src/tools/clippy/tests/ui/missing_trait_methods.stderr38
-rw-r--r--src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed8
-rw-r--r--src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs8
-rw-r--r--src/tools/clippy/tests/ui/needless_pub_self.stderr11
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs6
-rw-r--r--src/tools/clippy/tests/ui/patterns.fixed2
-rw-r--r--src/tools/clippy/tests/ui/patterns.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed131
-rw-r--r--src/tools/clippy/tests/ui/rename.rs131
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr158
-rw-r--r--src/tools/clippy/tests/ui/set_contains_or_insert.rs83
-rw-r--r--src/tools/clippy/tests/ui/set_contains_or_insert.stderr72
-rw-r--r--src/tools/clippy/tests/ui/single_match.fixed43
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs49
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr20
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.fixed2
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.rs2
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.stderr4
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.fixed17
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.rs17
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.stderr14
-rw-r--r--src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr47
-rw-r--r--src/tools/clippy/tests/ui/try_err.fixed10
-rw-r--r--src/tools/clippy/tests/ui/try_err.rs10
-rw-r--r--src/tools/clippy/tests/ui/uninit_vec.rs7
-rw-r--r--src/tools/clippy/tests/ui/uninit_vec.stderr38
-rw-r--r--src/tools/clippy/tests/ui/unneeded_field_pattern.rs2
-rw-r--r--src/tools/clippy/tests/ui/unused_result_ok.fixed40
-rw-r--r--src/tools/clippy/tests/ui/unused_result_ok.rs40
-rw-r--r--src/tools/clippy/tests/ui/unused_result_ok.stderr52
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.rs2
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.fixed9
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.rs9
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.stderr8
-rw-r--r--src/tools/clippy/tests/versioncheck.rs1
-rw-r--r--src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml3
-rw-r--r--src/tools/clippy/util/gh-pages/index.html4
-rw-r--r--src/tools/clippy/util/gh-pages/script.js74
-rw-r--r--src/tools/collect-license-metadata/Cargo.toml2
-rw-r--r--src/tools/collect-license-metadata/src/main.rs5
-rw-r--r--src/tools/compiletest/src/command-list.rs4
-rw-r--r--src/tools/compiletest/src/header.rs13
-rw-r--r--src/tools/compiletest/src/runtest.rs92
-rw-r--r--src/tools/compiletest/src/runtest/coverage.rs2
-rw-r--r--src/tools/generate-copyright/Cargo.toml4
-rw-r--r--src/tools/generate-copyright/src/cargo_metadata.rs191
-rw-r--r--src/tools/generate-copyright/src/main.rs101
-rw-r--r--src/tools/generate-copyright/templates/COPYRIGHT.html54
-rw-r--r--src/tools/generate-copyright/templates/Node.html71
-rw-r--r--src/tools/miri/Cargo.lock237
-rw-r--r--src/tools/miri/Cargo.toml11
-rw-r--r--src/tools/miri/README.md15
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock153
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml2
-rw-r--r--src/tools/miri/miri-script/src/commands.rs5
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs74
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs3
-rw-r--r--src/tools/miri/src/concurrency/thread.rs8
-rw-r--r--src/tools/miri/src/eval.rs40
-rw-r--r--src/tools/miri/src/helpers.rs65
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs4
-rw-r--r--src/tools/miri/src/lib.rs1
-rw-r--r--src/tools/miri/src/machine.rs47
-rw-r--r--src/tools/miri/src/shims/backtrace.rs4
-rw-r--r--src/tools/miri/src/shims/panic.rs30
-rw-r--r--src/tools/miri/src/shims/time.rs16
-rw-r--r--src/tools/miri/src/shims/tls.rs8
-rw-r--r--src/tools/miri/src/shims/unix/env.rs46
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs150
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs153
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs238
-rw-r--r--src/tools/miri/src/shims/unix/linux/epoll.rs2
-rw-r--r--src/tools/miri/src/shims/unix/linux/eventfd.rs2
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs8
-rw-r--r--src/tools/miri/src/shims/unix/socket.rs4
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs94
-rw-r--r--src/tools/miri/src/shims/unix/thread.rs23
-rw-r--r--src/tools/miri/src/shims/windows/env.rs4
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs8
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock217
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr10
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr10
-rw-r--r--src/tools/miri/tests/fail-dep/tokio/sleep.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_calls/check_callback_abi.rs2
-rw-r--r--src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr4
-rw-r--r--src/tools/miri/tests/fail/miri_start_wrong_sig.rs21
-rw-r--r--src/tools/miri/tests/fail/miri_start_wrong_sig.stderr15
-rw-r--r--src/tools/miri/tests/fail/no_main.rs2
-rw-r--r--src/tools/miri/tests/fail/no_main.stderr9
-rw-r--r--src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs8
-rw-r--r--src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr15
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs70
-rw-r--r--src/tools/miri/tests/pass/alloc-access-tracking.rs4
-rw-r--r--src/tools/miri/tests/pass/async-fn.rs1
-rw-r--r--src/tools/miri/tests/pass/enums.rs1
-rw-r--r--src/tools/miri/tests/pass/miri_start.rs19
-rw-r--r--src/tools/miri/tests/pass/miri_start.stdout1
-rw-r--r--src/tools/miri/tests/ui.rs2
-rw-r--r--src/tools/run-make-support/src/artifact_names.rs11
-rw-r--r--src/tools/run-make-support/src/external_deps/c_build.rs31
-rw-r--r--src/tools/run-make-support/src/external_deps/cc.rs21
-rw-r--r--src/tools/run-make-support/src/external_deps/clang.rs5
-rw-r--r--src/tools/run-make-support/src/external_deps/cygpath.rs35
-rw-r--r--src/tools/run-make-support/src/external_deps/llvm.rs9
-rw-r--r--src/tools/run-make-support/src/external_deps/mod.rs3
-rw-r--r--src/tools/run-make-support/src/fs.rs26
-rw-r--r--src/tools/run-make-support/src/lib.rs9
-rw-r--r--src/tools/run-make-support/src/path_helpers.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs1
-rw-r--r--src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs9
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs9
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt22
-rw-r--r--src/tools/tidy/src/deps.rs106
-rw-r--r--src/tools/tidy/src/edition.rs16
-rw-r--r--tests/assembly/x86-return-float.rs54
-rw-r--r--tests/codegen-units/item-collection/generic-impl.rs10
-rw-r--r--tests/codegen-units/item-collection/overloaded-operators.rs24
-rw-r--r--tests/codegen/aarch64-struct-align-128.rs30
-rw-r--r--tests/codegen/cold-call-declare-and-call.rs10
-rw-r--r--tests/codegen/default-requires-uwtable.rs10
-rw-r--r--tests/codegen/instrument-coverage/testprog.rs30
-rw-r--r--tests/codegen/issues/issue-107681-unwrap_unchecked.rs20
-rw-r--r--tests/codegen/issues/issue-118306.rs23
-rw-r--r--tests/codegen/issues/issue-122600-ptr-discriminant-update.rs19
-rw-r--r--tests/codegen/issues/issue-126585.rs24
-rw-r--r--tests/codegen/iter-repeat-n-trivial-drop.rs15
-rw-r--r--tests/codegen/repr/transparent-sysv64.rs6
-rw-r--r--tests/codegen/simd/issue-120720-reduce-nan.rs21
-rw-r--r--tests/codegen/sse42-implies-crc32.rs2
-rw-r--r--tests/codegen/target-feature-overrides.rs8
-rw-r--r--tests/codegen/tied-features-strength.rs2
-rw-r--r--tests/crashes/121127.rs2
-rw-r--r--tests/crashes/122909.rs15
-rw-r--r--tests/crashes/126272.rs28
-rw-r--r--tests/crashes/126896.rs2
-rw-r--r--tests/crashes/127299.rs12
-rw-r--r--tests/crashes/128094.rs14
-rw-r--r--tests/crashes/128176.rs13
-rw-r--r--tests/crashes/128190.rs7
-rw-r--r--tests/crashes/128327.rs5
-rw-r--r--tests/crashes/128346.rs13
-rw-r--r--tests/debuginfo/thread-names.rs4
-rw-r--r--tests/mir-opt/building/custom/terminators.rs12
-rw-r--r--tests/mir-opt/building/custom/terminators.tail_call.built.after.mir11
-rw-r--r--tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir10
-rw-r--r--tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir15
-rw-r--r--tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir17
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff61
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff37
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff37
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff37
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff52
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff47
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff52
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff47
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff77
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff72
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff77
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff72
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff67
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff62
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff67
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff62
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff32
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff26
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff32
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff31
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff47
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff80
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff74
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff42
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff42
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff42
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff38
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff37
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff37
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff47
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff42
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff47
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff42
-rw-r--r--tests/mir-opt/matches_reduce_branches.rs578
-rw-r--r--tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff41
-rw-r--r--tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff41
-rw-r--r--tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff16
-rw-r--r--tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff16
-rw-r--r--tests/mir-opt/unreachable.rs10
-rw-r--r--tests/mir-opt/unreachable_enum_branching.rs2
-rw-r--r--tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff24
-rw-r--r--tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff24
-rw-r--r--tests/run-make/cdylib-dylib-linkage/Makefile31
-rw-r--r--tests/run-make/cdylib-dylib-linkage/rmake.rs41
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions-1.rs6
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions-2.rs6
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions.rs8
-rw-r--r--tests/run-make/crate-loading/rmake.rs27
-rw-r--r--tests/run-make/cross-lang-lto-clang/Makefile25
-rw-r--r--tests/run-make/cross-lang-lto-clang/rmake.rs62
-rw-r--r--tests/run-make/cross-lang-lto-pgo-smoketest-clang/clib.c (renamed from tests/run-make/cross-lang-lto-pgo-smoketest/clib.c)0
-rw-r--r--tests/run-make/cross-lang-lto-pgo-smoketest-clang/cmain.c (renamed from tests/run-make/cross-lang-lto-pgo-smoketest/cmain.c)0
-rw-r--r--tests/run-make/cross-lang-lto-pgo-smoketest-clang/main.rs (renamed from tests/run-make/cross-lang-lto-pgo-smoketest/main.rs)0
-rw-r--r--tests/run-make/cross-lang-lto-pgo-smoketest-clang/rmake.rs120
-rw-r--r--tests/run-make/cross-lang-lto-pgo-smoketest-clang/rustlib.rs (renamed from tests/run-make/cross-lang-lto-pgo-smoketest/rustlib.rs)0
-rw-r--r--tests/run-make/cross-lang-lto-pgo-smoketest/Makefile90
-rw-r--r--tests/run-make/cross-lang-lto-riscv-abi/rmake.rs7
-rw-r--r--tests/run-make/cross-lang-lto-upstream-rlibs/Makefile32
-rw-r--r--tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs57
-rw-r--r--tests/run-make/dos-device-input/rmake.rs13
-rw-r--r--tests/run-make/dump-ice-to-disk/rmake.rs88
-rw-r--r--tests/run-make/fmt-write-bloat/main.rs2
-rw-r--r--tests/run-make/fmt-write-bloat/rmake.rs7
-rw-r--r--tests/run-make/issue-88756-default-output/Makefile4
-rw-r--r--tests/run-make/issue-88756-default-output/README.md1
-rw-r--r--tests/run-make/issue-88756-default-output/x.rs1
-rw-r--r--tests/run-make/link-args-order/rmake.rs11
-rw-r--r--tests/run-make/link-cfg/Makefile23
-rw-r--r--tests/run-make/link-cfg/rmake.rs43
-rw-r--r--tests/run-make/link-dedup/rmake.rs33
-rw-r--r--tests/run-make/long-linker-command-lines-cmd-exe/Makefile7
-rw-r--r--tests/run-make/long-linker-command-lines-cmd-exe/foo.rs26
-rw-r--r--tests/run-make/long-linker-command-lines-cmd-exe/rmake.rs26
-rw-r--r--tests/run-make/long-linker-command-lines/Makefile8
-rw-r--r--tests/run-make/long-linker-command-lines/foo.rs18
-rw-r--r--tests/run-make/long-linker-command-lines/rmake.rs19
-rw-r--r--tests/run-make/mte-ffi/bar.h43
-rw-r--r--tests/run-make/mte-ffi/bar_float.c44
-rw-r--r--tests/run-make/mte-ffi/bar_function.c39
-rw-r--r--tests/run-make/mte-ffi/bar_int.c47
-rw-r--r--tests/run-make/mte-ffi/bar_string.c48
-rw-r--r--tests/run-make/mte-ffi/foo_float.rs19
-rw-r--r--tests/run-make/mte-ffi/foo_function.rs17
-rw-r--r--tests/run-make/mte-ffi/foo_int.rs19
-rw-r--r--tests/run-make/mte-ffi/foo_string.rs27
-rw-r--r--tests/run-make/mte-ffi/rmake.rs38
-rw-r--r--tests/run-make/naked-symbol-visibility/a_rust_dylib.rs89
-rw-r--r--tests/run-make/naked-symbol-visibility/rmake.rs98
-rw-r--r--tests/run-make/no-duplicate-libs/main.rs6
-rw-r--r--tests/run-make/no-duplicate-libs/rmake.rs3
-rw-r--r--tests/run-make/pdb-buildinfo-cl-cmd/Makefile16
-rw-r--r--tests/run-make/pdb-buildinfo-cl-cmd/rmake.rs39
-rw-r--r--tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt1
-rw-r--r--tests/run-make/pgo-gen-lto/Makefile11
-rw-r--r--tests/run-make/pgo-gen-lto/rmake.rs22
-rw-r--r--tests/run-make/pgo-indirect-call-promotion/Makefile23
-rw-r--r--tests/run-make/pgo-indirect-call-promotion/rmake.rs33
-rw-r--r--tests/run-make/print-calling-conventions/Makefile4
-rw-r--r--tests/run-make/print-cfg/rmake.rs5
-rw-r--r--tests/run-make/print-check-cfg/rmake.rs2
-rw-r--r--tests/run-make/print-target-list/Makefile8
-rw-r--r--tests/run-make/print-target-list/rmake.rs21
-rw-r--r--tests/run-make/print-to-output/rmake.rs5
-rw-r--r--tests/run-make/raw-dylib-alt-calling-convention/Makefile24
-rw-r--r--tests/run-make/raw-dylib-alt-calling-convention/rmake.rs32
-rw-r--r--tests/run-make/raw-dylib-c/Makefile28
-rw-r--r--tests/run-make/raw-dylib-c/rmake.rs29
-rw-r--r--tests/run-make/redundant-libs/Makefile24
-rw-r--r--tests/run-make/redundant-libs/foo.c10
-rw-r--r--tests/run-make/redundant-libs/rmake.rs28
-rw-r--r--tests/run-make/reproducible-build-2/Makefile27
-rw-r--r--tests/run-make/reproducible-build-2/rmake.rs47
-rw-r--r--tests/run-make/rust-lld-compress-debug-sections/main.rs1
-rw-r--r--tests/run-make/rust-lld-compress-debug-sections/rmake.rs39
-rw-r--r--tests/run-make/rust-lld/rmake.rs14
-rw-r--r--tests/run-make/rustdoc-default-output/output-default.stdout (renamed from tests/run-make/issue-88756-default-output/output-default.stdout)0
-rw-r--r--tests/run-make/rustdoc-default-output/rmake.rs16
-rw-r--r--tests/run-make/rustdoc-scrape-examples-macros/rmake.rs3
-rw-r--r--tests/run-make/simd-ffi/Makefile47
-rw-r--r--tests/run-make/simd-ffi/rmake.rs63
-rw-r--r--tests/run-make/stable-symbol-names/Makefile41
-rw-r--r--tests/run-make/stable-symbol-names/rmake.rs68
-rw-r--r--tests/run-make/staticlib-dylib-linkage/Makefile21
-rw-r--r--tests/run-make/staticlib-dylib-linkage/rmake.rs36
-rw-r--r--tests/run-make/symbol-visibility/rmake.rs76
-rw-r--r--tests/run-make/thumb-none-cortex-m/Makefile38
-rw-r--r--tests/run-make/thumb-none-cortex-m/rmake.rs59
-rw-r--r--tests/run-make/thumb-none-qemu/Makefile27
-rw-r--r--tests/run-make/thumb-none-qemu/example/.cargo/config.toml (renamed from tests/run-make/thumb-none-qemu/example/.cargo/config)5
-rw-r--r--tests/run-make/thumb-none-qemu/rmake.rs62
-rw-r--r--tests/run-make/thumb-none-qemu/script.sh20
-rw-r--r--tests/run-make/used/rmake.rs8
-rw-r--r--tests/run-make/used/used.rs2
-rw-r--r--tests/run-make/wasm-override-linker/rmake.rs4
-rw-r--r--tests/run-make/zero-extend-abi-param-passing/param_passing.rs2
-rw-r--r--tests/run-make/zero-extend-abi-param-passing/rmake.rs15
-rw-r--r--tests/rustdoc-gui/search-result-impl-disambiguation.goml21
-rw-r--r--tests/rustdoc-gui/src/lib2/another_mod/mod.rs20
-rw-r--r--tests/rustdoc-js/self-is-not-generic.js22
-rw-r--r--tests/rustdoc-js/self-is-not-generic.rs11
-rw-r--r--tests/rustdoc-json/impls/pub_for_hidden_private.rs10
-rw-r--r--tests/rustdoc-json/pub_mod_in_private_mod.rs6
-rw-r--r--tests/rustdoc-json/the_smallest.rs5
-rw-r--r--tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs12
-rw-r--r--tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout5
-rw-r--r--tests/rustdoc-ui/intra-doc/.gitattributes2
-rw-r--r--tests/rustdoc-ui/intra-doc/warning-crlf.rs52
-rw-r--r--tests/rustdoc-ui/issues/issue-81662-shortness.rs2
-rw-r--r--tests/rustdoc-ui/issues/issue-81662-shortness.stdout2
-rw-r--r--tests/rustdoc-ui/remap-path-prefix-lint.rs10
-rw-r--r--tests/rustdoc-ui/remap-path-prefix-lint.stderr14
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs2
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs4
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs16
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/q.rs5
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/t.rs7
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-transitive/s.rs24
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-two-no-index/auxiliary/f.rs2
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs14
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs5
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-two/e.rs21
-rw-r--r--tests/rustdoc/cross-crate-info/index-on-last/auxiliary/f.rs2
-rw-r--r--tests/rustdoc/cross-crate-info/index-on-last/e.rs20
-rw-r--r--tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/q.rs5
-rw-r--r--tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/r.rs7
-rw-r--r--tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/s.rs8
-rw-r--r--tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/t.rs7
-rw-r--r--tests/rustdoc/cross-crate-info/kitchen-sink/i.rs30
-rw-r--r--tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs12
-rw-r--r--tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs6
-rw-r--r--tests/rustdoc/cross-crate-info/transitive/auxiliary/q.rs2
-rw-r--r--tests/rustdoc/cross-crate-info/transitive/auxiliary/t.rs4
-rw-r--r--tests/rustdoc/cross-crate-info/transitive/s.rs6
-rw-r--r--tests/rustdoc/cross-crate-info/two/auxiliary/f.rs2
-rw-r--r--tests/rustdoc/cross-crate-info/two/e.rs6
-rw-r--r--tests/rustdoc/cross-crate-info/working-dir-examples/q.rs10
-rw-r--r--tests/rustdoc/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs3
-rw-r--r--tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs14
-rw-r--r--tests/rustdoc/negative-impl-no-items.rs26
-rw-r--r--tests/rustdoc/unsafe-extern-blocks.rs3
-rw-r--r--tests/ui/asm/aarch64/type-check-2.rs18
-rw-r--r--tests/ui/asm/aarch64/type-check-2.stderr34
-rw-r--r--tests/ui/asm/invalid-const-operand.rs51
-rw-r--r--tests/ui/asm/invalid-const-operand.stderr86
-rw-r--r--tests/ui/asm/invalid-sym-operand.rs34
-rw-r--r--tests/ui/asm/invalid-sym-operand.stderr26
-rw-r--r--tests/ui/asm/parse-error.rs15
-rw-r--r--tests/ui/asm/parse-error.stderr40
-rw-r--r--tests/ui/asm/type-check-1.rs46
-rw-r--r--tests/ui/asm/type-check-1.stderr88
-rw-r--r--tests/ui/asm/x86_64/type-check-2.rs20
-rw-r--r--tests/ui/asm/x86_64/type-check-2.stderr42
-rw-r--r--tests/ui/associated-type-bounds/name-same-as-generic-type-issue-128249.rs15
-rw-r--r--tests/ui/associated-type-bounds/name-same-as-generic-type-issue-128249.stderr51
-rw-r--r--tests/ui/async-await/async-closures/fn-exception-target-features.rs17
-rw-r--r--tests/ui/async-await/async-closures/fn-exception-target-features.stderr17
-rw-r--r--tests/ui/async-await/async-closures/fn-exception.rs21
-rw-r--r--tests/ui/async-await/async-closures/fn-exception.stderr31
-rw-r--r--tests/ui/async-await/async-closures/non-copy-arg-does-not-force-inner-move.rs17
-rw-r--r--tests/ui/async-await/in-trait/generics-mismatch.rs2
-rw-r--r--tests/ui/async-await/in-trait/generics-mismatch.stderr2
-rw-r--r--tests/ui/attributes/check-builtin-attr-ice.rs58
-rw-r--r--tests/ui/attributes/check-builtin-attr-ice.stderr21
-rw-r--r--tests/ui/attributes/check-cfg_attr-ice.rs68
-rw-r--r--tests/ui/attributes/check-cfg_attr-ice.stderr101
-rw-r--r--tests/ui/attributes/no-sanitize.rs34
-rw-r--r--tests/ui/attributes/no-sanitize.stderr55
-rw-r--r--tests/ui/cast/dyn-tails-need-normalization.rs21
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs-allow.rs4
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.debug_assertions_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.overflow_checks_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.panic_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.proc_macro_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.relocation_model_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.rs35
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.sanitize_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.sanitizer_cfi_generalize_pointers_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.sanitizer_cfi_normalize_integers_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_abi_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_arch_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_endian_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_env_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_family_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_feature_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_equal_alignment_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_load_store_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_os_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_pointer_width_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_thread_local_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.target_vendor_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.test_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.ub_checks_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.unix_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.windows_.stderr8
-rw-r--r--tests/ui/check-cfg/mix.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs3
-rw-r--r--tests/ui/codemap_tests/huge_multispan_highlight.svg2
-rw-r--r--tests/ui/coherence/re-rebalance-coherence.rs1
-rw-r--r--tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.rs28
-rw-r--r--tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr160
-rw-r--r--tests/ui/const-generics/cross_crate_complex.rs1
-rw-r--r--tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs10
-rw-r--r--tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr10
-rw-r--r--tests/ui/const-generics/defaults/repr-c-issue-82792.rs1
-rw-r--r--tests/ui/const-generics/generic_const_exprs/associated-consts.rs3
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-80742.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/no_where_clause.rs1
-rw-r--r--tests/ui/const-generics/generic_const_exprs/no_where_clause.stderr13
-rw-r--r--tests/ui/const-generics/issues/issue-86535-2.rs1
-rw-r--r--tests/ui/const-generics/issues/issue-86535.rs1
-rw-r--r--tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs1
-rw-r--r--tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs4
-rw-r--r--tests/ui/coroutine/invalid_attr_usage.rs11
-rw-r--r--tests/ui/coroutine/invalid_attr_usage.stderr14
-rw-r--r--tests/ui/delegation/not-supported.rs2
-rw-r--r--tests/ui/delegation/not-supported.stderr6
-rw-r--r--tests/ui/derives/deriving-with-repr-packed.rs11
-rw-r--r--tests/ui/derives/deriving-with-repr-packed.stderr74
-rw-r--r--tests/ui/deriving/deriving-all-codegen.rs10
-rw-r--r--tests/ui/deriving/deriving-all-codegen.stderr63
-rw-r--r--tests/ui/deriving/deriving-all-codegen.stdout20
-rw-r--r--tests/ui/enum-discriminant/issue-61696.rs1
-rw-r--r--tests/ui/enum-discriminant/niche.rs1
-rw-r--r--tests/ui/error-codes/E0049.stderr4
-rw-r--r--tests/ui/error-codes/E0195.rs4
-rw-r--r--tests/ui/error-codes/E0195.stderr6
-rw-r--r--tests/ui/error-codes/E0283.stderr8
-rw-r--r--tests/ui/error-codes/E0790.stderr8
-rw-r--r--tests/ui/extern/extern-types-field-offset.run.stderr2
-rw-r--r--tests/ui/extern/extern-types-size_of_val.align.run.stderr2
-rw-r--r--tests/ui/extern/extern-types-size_of_val.size.run.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.stderr21
-rw-r--r--tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr10
-rw-r--r--tests/ui/feature-gates/feature-gate-sha512_sm_x86.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-sha512_sm_x86.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs13
-rw-r--r--tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr23
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs1
-rw-r--r--tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr17
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs2
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-71176.rs2
-rw-r--r--tests/ui/generic-associated-types/issue-71176.stderr18
-rw-r--r--tests/ui/generic-associated-types/missing-bounds.fixed4
-rw-r--r--tests/ui/generic-associated-types/missing-bounds.rs4
-rw-r--r--tests/ui/generic-associated-types/missing-bounds.stderr18
-rw-r--r--tests/ui/hygiene/panic-location.run.stderr2
-rw-r--r--tests/ui/impl-trait/extra-impl-in-trait-impl.fixed2
-rw-r--r--tests/ui/impl-trait/extra-impl-in-trait-impl.rs2
-rw-r--r--tests/ui/impl-trait/extra-impl-in-trait-impl.stderr8
-rw-r--r--tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs29
-rw-r--r--tests/ui/impl-trait/in-trait/cannot-capture-intersection.stderr13
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr2
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr9
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr9
-rw-r--r--tests/ui/impl-trait/where-allowed.stderr22
-rw-r--r--tests/ui/inline-const/using-late-bound-from-closure.rs16
-rw-r--r--tests/ui/inline-const/using-late-bound-from-closure.stderr19
-rw-r--r--tests/ui/issues/issue-19380.rs1
-rw-r--r--tests/ui/issues/issue-19380.stderr25
-rw-r--r--tests/ui/issues/issue-26812.rs4
-rw-r--r--tests/ui/issues/issue-26812.stderr25
-rw-r--r--tests/ui/issues/issue-5708.rs1
-rw-r--r--tests/ui/json/json-bom-plus-crlf-multifile.stderr8
-rw-r--r--tests/ui/json/json-bom-plus-crlf.stderr8
-rw-r--r--tests/ui/json/json-short.stderr2
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.stderr11
-rw-r--r--tests/ui/lint/command-line-lint-group-forbid.stderr1
-rw-r--r--tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs33
-rw-r--r--tests/ui/lint/dead-code/issue-59003.rs2
-rw-r--r--tests/ui/lint/dead-code/lint-dead-code-1.rs5
-rw-r--r--tests/ui/lint/dead-code/lint-dead-code-1.stderr26
-rw-r--r--tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs37
-rw-r--r--tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr20
-rw-r--r--tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs32
-rw-r--r--tests/ui/lint/dead-code/unconstructible-pub-struct.rs35
-rw-r--r--tests/ui/lint/dead-code/unconstructible-pub-struct.stderr14
-rw-r--r--tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs36
-rw-r--r--tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr20
-rw-r--r--tests/ui/lint/dead-code/unused-assoc-const.rs20
-rw-r--r--tests/ui/lint/dead-code/unused-assoc-const.stderr16
-rw-r--r--tests/ui/lint/dead-code/unused-impl-for-non-adts.rs45
-rw-r--r--tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr20
-rw-r--r--tests/ui/lint/dead-code/unused-pub-struct.rs48
-rw-r--r--tests/ui/lint/dead-code/unused-pub-struct.stderr14
-rw-r--r--tests/ui/lint/dead-code/unused-struct-derive-default.rs1
-rw-r--r--tests/ui/lint/dead-code/unused-struct-derive-default.stderr1
-rw-r--r--tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs11
-rw-r--r--tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr20
-rw-r--r--tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr1
-rw-r--r--tests/ui/lint/force-warn/lint-group-allow-warnings.stderr1
-rw-r--r--tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr1
-rw-r--r--tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr1
-rw-r--r--tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr1
-rw-r--r--tests/ui/lint/group-forbid-always-trumps-cli.stderr1
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.fixed8
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.rs8
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.stderr88
-rw-r--r--tests/ui/lint/unaligned_references.current.stderr (renamed from tests/ui/lint/unaligned_references.stderr)26
-rw-r--r--tests/ui/lint/unaligned_references.next.stderr133
-rw-r--r--tests/ui/lint/unaligned_references.rs26
-rw-r--r--tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs1
-rw-r--r--tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr4
-rw-r--r--tests/ui/never_type/never-result.rs5
-rw-r--r--tests/ui/offset-of/offset-of-slice-normalized.rs37
-rw-r--r--tests/ui/panics/panic-in-cleanup.run.stderr2
-rw-r--r--tests/ui/panics/panic-in-ffi.run.stderr2
-rw-r--r--tests/ui/parser/issues/issue-105366.fixed1
-rw-r--r--tests/ui/parser/issues/issue-105366.rs1
-rw-r--r--tests/ui/parser/issues/issue-105366.stderr2
-rw-r--r--tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed3
-rw-r--r--tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs3
-rw-r--r--tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr10
-rw-r--r--tests/ui/parser/suggest-remove-compount-assign-let-ice.rs16
-rw-r--r--tests/ui/parser/suggest-remove-compount-assign-let-ice.stderr26
-rw-r--r--tests/ui/parser/unsafe-foreign-mod-2.rs2
-rw-r--r--tests/ui/parser/unsafe-foreign-mod-2.stderr18
-rw-r--r--tests/ui/parser/unsafe-foreign-mod.rs6
-rw-r--r--tests/ui/parser/unsafe-foreign-mod.stderr12
-rw-r--r--tests/ui/pattern/issue-22546.rs2
-rw-r--r--tests/ui/pattern/issue-22546.stderr10
-rw-r--r--tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr6
-rw-r--r--tests/ui/pattern/usefulness/always-inhabited-union-ref.normal.stderr (renamed from tests/ui/pattern/usefulness/always-inhabited-union-ref.min_exhaustive_patterns.stderr)6
-rw-r--r--tests/ui/pattern/usefulness/always-inhabited-union-ref.rs3
-rw-r--r--tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr6
-rw-r--r--tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr7
-rw-r--r--tests/ui/pattern/usefulness/empty-match-check-notes.rs6
-rw-r--r--tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr93
-rw-r--r--tests/ui/pattern/usefulness/empty-match.normal.stderr93
-rw-r--r--tests/ui/pattern/usefulness/empty-match.rs7
-rw-r--r--tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr100
-rw-r--r--tests/ui/pattern/usefulness/empty-types.never_pats.stderr357
-rw-r--r--tests/ui/pattern/usefulness/empty-types.normal.stderr355
-rw-r--r--tests/ui/pattern/usefulness/empty-types.rs92
-rw-r--r--tests/ui/pattern/usefulness/explain-unreachable-pats.rs1
-rw-r--r--tests/ui/pattern/usefulness/explain-unreachable-pats.stderr24
-rw-r--r--tests/ui/pattern/usefulness/impl-trait.rs1
-rw-r--r--tests/ui/pattern/usefulness/impl-trait.stderr32
-rw-r--r--tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr2
-rw-r--r--tests/ui/pattern/usefulness/match-privately-empty.normal.stderr21
-rw-r--r--tests/ui/pattern/usefulness/match-privately-empty.rs3
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr2
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.normal.stderr30
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.rs7
-rw-r--r--tests/ui/pattern/usefulness/uninhabited.rs1
-rw-r--r--tests/ui/polymorphization/inline-tainted-body.rs21
-rw-r--r--tests/ui/polymorphization/inline-tainted-body.stderr30
-rw-r--r--tests/ui/print-calling-conventions.rs2
-rw-r--r--tests/ui/print-calling-conventions.stdout34
-rw-r--r--tests/ui/process/println-with-broken-pipe.run.stderr2
-rw-r--r--tests/ui/pub/pub-ident-struct-4.fixed3
-rw-r--r--tests/ui/pub/pub-ident-struct-4.rs3
-rw-r--r--tests/ui/pub/pub-ident-struct-4.stderr6
-rw-r--r--tests/ui/reachable/unreachable-loop-patterns.rs2
-rw-r--r--tests/ui/reachable/unreachable-loop-patterns.stderr4
-rw-r--r--tests/ui/regions/regions-issue-21422.rs1
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/check.rs8
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/check.stderr22
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr16
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs1
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr14
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.normal.stderr44
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs15
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr55
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs11
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr79
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs7
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr64
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr10
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs7
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr34
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr4
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/auxiliary/edition-lint-infer-outlives-macro.rs (renamed from tests/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.stderr (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.rs (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.stderr (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.fixed (renamed from tests/ui/rust-2018/edition-lint-infer-outlives.fixed)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.rs (renamed from tests/ui/rust-2018/edition-lint-infer-outlives.rs)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.stderr (renamed from tests/ui/rust-2018/edition-lint-infer-outlives.stderr)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.fixed41
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.rs41
-rw-r--r--tests/ui/rust-2024/safe-outside-extern.rs8
-rw-r--r--tests/ui/rust-2024/safe-outside-extern.stderr38
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr4
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr4
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs2
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr2
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs2
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs3
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.stderr (renamed from tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr)2
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs2
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs3
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr8
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr4
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr6
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs2
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed1
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs1
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr4
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr4
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr4
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs2
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed1
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs1
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr2
-rw-r--r--tests/ui/sanitizer/cfi-can-reveal-opaques.rs44
-rw-r--r--tests/ui/short-error-format.stderr4
-rw-r--r--tests/ui/specialization/const_trait_impl.stderr10
-rw-r--r--tests/ui/static/static-lifetime.rs1
-rw-r--r--tests/ui/static/static-lifetime.stderr30
-rw-r--r--tests/ui/statics/unsizing-wfcheck-issue-127299.rs17
-rw-r--r--tests/ui/statics/unsizing-wfcheck-issue-127299.stderr87
-rw-r--r--tests/ui/structs-enums/newtype-struct-with-dtor.rs2
-rw-r--r--tests/ui/structs-enums/uninstantiable-struct.rs3
-rw-r--r--tests/ui/structs/field-implied-unsizing-wfcheck.rs32
-rw-r--r--tests/ui/structs/field-implied-unsizing-wfcheck.stderr163
-rw-r--r--tests/ui/suggestions/derive-clone-for-eq.fixed1
-rw-r--r--tests/ui/suggestions/derive-clone-for-eq.rs1
-rw-r--r--tests/ui/suggestions/derive-clone-for-eq.stderr4
-rw-r--r--tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr9
-rw-r--r--tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr10
-rw-r--r--tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr10
-rw-r--r--tests/ui/suggestions/option-content-move.fixed2
-rw-r--r--tests/ui/suggestions/option-content-move.rs2
-rw-r--r--tests/ui/suggestions/option-content-move.stderr4
-rw-r--r--tests/ui/target-feature/asm-implied-features-issue-128125.rs10
-rw-r--r--tests/ui/target-feature/implicit-features-cli.rs9
-rw-r--r--tests/ui/target-feature/implicit-features.rs10
-rw-r--r--tests/ui/target-feature/implied-features.rs24
-rw-r--r--tests/ui/target-feature/wasm-relaxed-simd.rs9
-rw-r--r--tests/ui/traits/object/generics.rs1
-rw-r--r--tests/ui/try-trait/try-operator-custom.rs3
-rw-r--r--tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr10
-rw-r--r--tests/ui/type/default_type_parameter_in_fn_or_impl.rs (renamed from tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.rs)0
-rw-r--r--tests/ui/type/default_type_parameter_in_fn_or_impl.stderr43
-rw-r--r--tests/ui/type/pattern_types/feature-gate-pattern_types.stderr5
-rw-r--r--tests/ui/typeck/issue-36708.stderr2
-rw-r--r--tests/ui/typeck/suggest-arg-comma-delete-ice.rs19
-rw-r--r--tests/ui/typeck/suggest-arg-comma-delete-ice.stderr38
-rw-r--r--tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs2
-rw-r--r--tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr4
-rw-r--r--tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr26
-rw-r--r--tests/ui/uninhabited/uninhabited-irrefutable.rs3
-rw-r--r--tests/ui/uninhabited/uninhabited-matches-feature-gated.rs7
-rw-r--r--tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr66
-rw-r--r--tests/ui/uninhabited/uninhabited-patterns.rs1
-rw-r--r--tests/ui/uninhabited/uninhabited-patterns.stderr8
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.rs1
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.stdout1
-rw-r--r--tests/ui/wf/wf-in-where-clause-static.current.stderr12
-rw-r--r--tests/ui/wf/wf-in-where-clause-static.next.stderr12
-rw-r--r--tests/ui/wf/wf-in-where-clause-static.rs10
-rw-r--r--triagebot.toml8
1264 files changed, 26714 insertions, 13701 deletions
diff --git a/.gitignore b/.gitignore
index 87d02563ed0..a36cb51de33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,9 @@ Session.vim
 *.iml
 .vscode
 .project
+.vim/
+.helix/
+.zed/
 .favorites.json
 .settings/
 .vs/
@@ -48,6 +51,7 @@ build/
 /dist/
 /unicode-downloads
 /target
+/library/target
 /src/bootstrap/target
 /src/tools/x/target
 # Created by default with `src/ci/docker/run.sh`
diff --git a/Cargo.lock b/Cargo.lock
index 316926e584e..4bd99b7fbe7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -12,26 +12,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "addr2line"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
-dependencies = [
- "compiler_builtins",
- "gimli 0.29.0",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
 name = "adler"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
 
 [[package]]
 name = "aes"
@@ -67,16 +51,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "alloc"
-version = "0.0.0"
-dependencies = [
- "compiler_builtins",
- "core",
- "rand",
- "rand_xorshift",
-]
-
-[[package]]
 name = "allocator-api2"
 version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -231,11 +205,11 @@ dependencies = [
 
 [[package]]
 name = "ar_archive_writer"
-version = "0.3.0"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8412a2d690663356cba5a2532f3ed55d1e8090743bc6695b88403b27df67733"
+checksum = "3f2bcb7cf51decfbbfc7ef476e28b0775b13e5eb1190f8b7df145cd53d4f4374"
 dependencies = [
- "object 0.35.0",
+ "object 0.36.2",
 ]
 
 [[package]]
@@ -256,7 +230,7 @@ version = "0.3.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
 dependencies = [
- "addr2line 0.21.0",
+ "addr2line",
  "cc",
  "cfg-if",
  "libc",
@@ -455,10 +429,6 @@ name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
 
 [[package]]
 name = "cfg_aliases"
@@ -594,7 +564,7 @@ dependencies = [
  "termize",
  "tokio",
  "toml 0.7.8",
- "ui_test 0.24.0",
+ "ui_test 0.25.0",
  "walkdir",
 ]
 
@@ -602,6 +572,7 @@ dependencies = [
 name = "clippy_config"
 version = "0.1.82"
 dependencies = [
+ "itertools",
  "rustc-semver",
  "serde",
  "toml 0.7.8",
@@ -738,16 +709,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335"
 
 [[package]]
-name = "compiler_builtins"
-version = "0.1.114"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb58b199190fcfe0846f55a3b545cd6b07a34bdd5930a476ff856f3ebcc5558a"
-dependencies = [
- "cc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
 name = "compiletest"
 version = "0.0.0"
 dependencies = [
@@ -788,14 +749,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "core"
-version = "0.0.0"
-dependencies = [
- "rand",
- "rand_xorshift",
-]
-
-[[package]]
 name = "core-foundation-sys"
 version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1135,19 +1088,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
 
 [[package]]
-name = "dlmalloc"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d"
-dependencies = [
- "cfg-if",
- "compiler_builtins",
- "libc",
- "rustc-std-workspace-core",
- "windows-sys 0.52.0",
-]
-
-[[package]]
 name = "either"
 version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1349,16 +1289,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "fortanix-sgx-abi"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
 name = "fs-err"
 version = "2.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1477,8 +1407,11 @@ name = "generate-copyright"
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "cargo_metadata 0.18.1",
+ "rinja",
  "serde",
  "serde_json",
+ "thiserror",
 ]
 
 [[package]]
@@ -1504,8 +1437,6 @@ version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
 dependencies = [
- "rustc-std-workspace-core",
- "rustc-std-workspace-std",
  "unicode-width",
 ]
 
@@ -1526,27 +1457,13 @@ version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 dependencies = [
- "compiler_builtins",
  "fallible-iterator",
  "indexmap",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
  "stable_deref_trait",
 ]
 
 [[package]]
 name = "gimli"
-version = "0.29.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "gimli"
 version = "0.31.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
@@ -1606,9 +1523,6 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 dependencies = [
  "ahash",
  "allocator-api2",
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
  "serde",
 ]
 
@@ -1631,17 +1545,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
 
 [[package]]
-name = "hermit-abi"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
 name = "hex"
 version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2065,9 +1968,6 @@ name = "libc"
 version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
-dependencies = [
- "rustc-std-workspace-core",
-]
 
 [[package]]
 name = "libdbus-sys"
@@ -2299,10 +2199,6 @@ name = "memchr"
 version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
 
 [[package]]
 name = "memmap2"
@@ -2357,9 +2253,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
 dependencies = [
  "adler",
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
 ]
 
 [[package]]
@@ -2393,6 +2286,7 @@ dependencies = [
  "smallvec",
  "tempfile",
  "ui_test 0.21.2",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -2540,7 +2434,7 @@ version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
- "hermit-abi 0.3.9",
+ "hermit-abi",
  "libc",
 ]
 
@@ -2566,27 +2460,15 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.35.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "object"
 version = "0.36.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
 dependencies = [
- "compiler_builtins",
  "crc32fast",
  "flate2",
  "hashbrown",
  "indexmap",
  "memchr",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
  "ruzstd 0.7.0",
  "wasmparser 0.214.0",
 ]
@@ -2711,29 +2593,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "panic_abort"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "cfg-if",
- "compiler_builtins",
- "core",
- "libc",
-]
-
-[[package]]
-name = "panic_unwind"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "cfg-if",
- "compiler_builtins",
- "core",
- "libc",
- "unwind",
-]
-
-[[package]]
 name = "papergrid"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2988,23 +2847,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "proc_macro"
-version = "0.0.0"
-dependencies = [
- "core",
- "std",
-]
-
-[[package]]
-name = "profiler_builtins"
-version = "0.0.0"
-dependencies = [
- "cc",
- "compiler_builtins",
- "core",
-]
-
-[[package]]
 name = "psm"
 version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3082,27 +2924,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "r-efi"
-version = "4.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "r-efi-alloc"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7"
-dependencies = [
- "compiler_builtins",
- "r-efi",
- "rustc-std-workspace-core",
-]
-
-[[package]]
 name = "rand"
 version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3133,15 +2954,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "rand_xorshift"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
 name = "rand_xoshiro"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3282,20 +3094,25 @@ dependencies = [
 
 [[package]]
 name = "rinja"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2d47a46d7729e891c8accf260e9daa02ae6d570aa2a94fb1fb27eb5364a2323"
+checksum = "6d3762e3740cdbf2fd2be465cc2c26d643ad17353cc2e0223d211c1b096118bd"
 dependencies = [
+ "humansize",
+ "itoa",
+ "num-traits",
+ "percent-encoding",
  "rinja_derive",
 ]
 
 [[package]]
 name = "rinja_derive"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44dae9afe59d58ed8d988d67d1945f3638125d2fd2104058399382e11bd3ea2a"
+checksum = "fd01fd8e15e7d19c8b8052c1d428325131e02ff1633cdcf695190c2e56ab682c"
 dependencies = [
  "basic-toml",
+ "memchr",
  "mime",
  "mime_guess",
  "once_map",
@@ -3308,10 +3125,11 @@ dependencies = [
 
 [[package]]
 name = "rinja_parser"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1771c78cd5d3b1646ef8d8f2ed100db936e8b291d3cc06e92a339ff346858c"
+checksum = "a2f6bf7cef118c6de21206edf0b3f19f5ede60006be674a58ca21b6e003a1b57"
 dependencies = [
+ "memchr",
  "nom",
 ]
 
@@ -3337,9 +3155,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.2"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa3ca63cc537c1cb69e4c2c0afc5fda2ccd36ac84c97d5a4ae05e69b1c834afb"
+checksum = "2471f8f296262437d7e848e527b4210b44a96e53a3b4435b890227ce3e6da106"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -3352,10 +3170,6 @@ name = "rustc-demangle"
 version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
 
 [[package]]
 name = "rustc-hash"
@@ -3417,27 +3231,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5c9f15eec8235d7cb775ee6f81891db79b98fd54ba1ad8fae565b88ef1ae4e2"
 
 [[package]]
-name = "rustc-std-workspace-alloc"
-version = "1.99.0"
-dependencies = [
- "alloc",
-]
-
-[[package]]
-name = "rustc-std-workspace-core"
-version = "1.99.0"
-dependencies = [
- "core",
-]
-
-[[package]]
-name = "rustc-std-workspace-std"
-version = "1.99.0"
-dependencies = [
- "std",
-]
-
-[[package]]
 name = "rustc_abi"
 version = "0.0.0"
 dependencies = [
@@ -4346,6 +4139,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "rustc_trait_selection",
+ "rustc_type_ir",
  "smallvec",
  "tracing",
 ]
@@ -5143,9 +4937,9 @@ dependencies = [
 
 [[package]]
 name = "spanned"
-version = "0.2.1"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d"
+checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6"
 dependencies = [
  "bstr",
  "color-eyre",
@@ -5223,46 +5017,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
 [[package]]
-name = "std"
-version = "0.0.0"
-dependencies = [
- "addr2line 0.22.0",
- "alloc",
- "cfg-if",
- "compiler_builtins",
- "core",
- "dlmalloc",
- "fortanix-sgx-abi",
- "hashbrown",
- "hermit-abi 0.4.0",
- "libc",
- "miniz_oxide",
- "object 0.36.2",
- "panic_abort",
- "panic_unwind",
- "profiler_builtins",
- "r-efi",
- "r-efi-alloc",
- "rand",
- "rand_xorshift",
- "rustc-demangle",
- "std_detect",
- "unwind",
- "wasi",
-]
-
-[[package]]
-name = "std_detect"
-version = "0.1.5"
-dependencies = [
- "cfg-if",
- "compiler_builtins",
- "libc",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
 name = "string_cache"
 version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5366,15 +5120,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "sysroot"
-version = "0.0.0"
-dependencies = [
- "proc_macro",
- "std",
- "test",
-]
-
-[[package]]
 name = "tabled"
 version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5459,16 +5204,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "test"
-version = "0.0.0"
-dependencies = [
- "core",
- "getopts",
- "libc",
- "std",
-]
-
-[[package]]
 name = "test-float-parse"
 version = "0.1.0"
 dependencies = [
@@ -5828,9 +5563,9 @@ dependencies = [
 
 [[package]]
 name = "ui_test"
-version = "0.24.0"
+version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc1c6c78d55482388711c8d417b8e547263046a607512278fed274c54633bbe4"
+checksum = "f7e4f339f62edc873975c47115f9e71c5454ddaa37c1142b42fc0b2672c8dacb"
 dependencies = [
  "annotate-snippets 0.11.4",
  "anyhow",
@@ -5966,11 +5701,6 @@ name = "unicode-width"
 version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
- "rustc-std-workspace-std",
-]
 
 [[package]]
 name = "unicode-xid"
@@ -5996,28 +5726,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "unwind"
-version = "0.0.0"
-dependencies = [
- "cfg-if",
- "compiler_builtins",
- "core",
- "libc",
- "unwinding",
-]
-
-[[package]]
-name = "unwinding"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b"
-dependencies = [
- "compiler_builtins",
- "gimli 0.28.1",
- "rustc-std-workspace-core",
-]
-
-[[package]]
 name = "url"
 version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6088,11 +5796,6 @@ name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
 
 [[package]]
 name = "wasm-bindgen"
diff --git a/Cargo.toml b/Cargo.toml
index 178a5ab9408..131feec70ab 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,8 +2,6 @@
 resolver = "1"
 members = [
   "compiler/rustc",
-  "library/std",
-  "library/sysroot",
   "src/etc/test-float-parse",
   "src/rustdoc-json-types",
   "src/tools/build_helper",
@@ -61,23 +59,8 @@ exclude = [
   # not all `Cargo.toml` files are available, so we exclude the `x` binary,
   # so it can be invoked before the current checkout is set up.
   "src/tools/x",
-  # stdarch has its own Cargo workspace
-  "library/stdarch",
 ]
 
-[profile.release.package.compiler_builtins]
-# For compiler-builtins we always use a high number of codegen units.
-# The goal here is to place every single intrinsic into its own object
-# file to avoid symbol clashes with the system libgcc if possible. Note
-# that this number doesn't actually produce this many object files, we
-# just don't create more than this number of object files.
-#
-# It's a bit of a bummer that we have to pass this here, unfortunately.
-# Ideally this would be specified through an env var to Cargo so Cargo
-# knows how many CGUs are for this specific crate, but for now
-# per-crate configuration isn't specifiable in the environment.
-codegen-units = 10000
-
 [profile.release.package.rustc-rayon-core]
 # The rustc fork of Rayon has deadlock detection code which intermittently
 # causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227)
@@ -85,19 +68,6 @@ codegen-units = 10000
 # FIXME: This workaround should be removed once #90227 is fixed.
 overflow-checks = false
 
-# These dependencies of the standard library implement symbolication for
-# backtraces on most platforms. Their debuginfo causes both linking to be slower
-# (more data to chew through) and binaries to be larger without really all that
-# much benefit. This section turns them all to down to have no debuginfo which
-# helps to improve link times a little bit.
-[profile.release.package]
-addr2line.debug = 0
-adler.debug = 0
-gimli.debug = 0
-miniz_oxide.debug = 0
-object.debug = 0
-rustc-demangle.debug = 0
-
 # These are very thin wrappers around executing lld with the right binary name.
 # Basically nothing within them can go wrong without having been explicitly logged anyway.
 # We ship these in every rustc tarball and even after compression they add up
@@ -120,10 +90,3 @@ codegen-units = 1
 # FIXME: LTO cannot be enabled for binaries in a workspace
 # <https://github.com/rust-lang/cargo/issues/9330>
 # lto = true
-
-[patch.crates-io]
-# See comments in `library/rustc-std-workspace-core/README.md` for what's going on
-# here
-rustc-std-workspace-core = { path = 'library/rustc-std-workspace-core' }
-rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' }
-rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' }
diff --git a/REUSE.toml b/REUSE.toml
index 1a30d8016c9..efd70555247 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -163,7 +163,7 @@ SPDX-License-Identifier = "MIT OR Apache-2.0"
 path = "src/llvm-project/**"
 precedence = "override"
 SPDX-FileCopyrightText = [
-    "2003-2019 by the contributors listed in [CREDITS.TXT](https://github.com/rust-lang/llvm-project/blob/7738295178045041669876bf32b0543ec8319a5c/llvm/CREDITS.TXT)",
+    "2003-2019 by the contributors listed in CREDITS.TXT (https://github.com/rust-lang/llvm-project/blob/7738295178045041669876bf32b0543ec8319a5c/llvm/CREDITS.TXT)",
     "2010 Apple Inc",
     "2003-2019 University of Illinois at Urbana-Champaign.",
 ]
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 1456890a0a2..7af3945d3f9 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1668,7 +1668,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             }),
                         )),
                     )),
-                    // FIXME(effects) we might not need a default.
                     default: Some(default_ct),
                     is_host_effect: true,
                     synthetic: true,
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index efcf274e511..a353c79f12d 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -453,11 +453,6 @@ impl<'a> AstValidator<'a> {
                             item_span: span,
                             block: Some(self.current_extern_span().shrink_to_lo()),
                         });
-                    } else if !self.features.unsafe_extern_blocks {
-                        self.dcx().emit_err(errors::InvalidSafetyOnExtern {
-                            item_span: span,
-                            block: None,
-                        });
                     }
                 }
             }
@@ -1054,32 +1049,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         errors::VisibilityNotPermittedNote::IndividualForeignItems,
                     );
 
-                    if this.features.unsafe_extern_blocks {
-                        if &Safety::Default == safety {
-                            if item.span.at_least_rust_2024() {
-                                this.dcx()
-                                    .emit_err(errors::MissingUnsafeOnExtern { span: item.span });
-                            } else {
-                                this.lint_buffer.buffer_lint(
-                                    MISSING_UNSAFE_ON_EXTERN,
-                                    item.id,
-                                    item.span,
-                                    BuiltinLintDiag::MissingUnsafeOnExtern {
-                                        suggestion: item.span.shrink_to_lo(),
-                                    },
-                                );
-                            }
+                    if &Safety::Default == safety {
+                        if item.span.at_least_rust_2024() {
+                            this.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span });
+                        } else {
+                            this.lint_buffer.buffer_lint(
+                                MISSING_UNSAFE_ON_EXTERN,
+                                item.id,
+                                item.span,
+                                BuiltinLintDiag::MissingUnsafeOnExtern {
+                                    suggestion: item.span.shrink_to_lo(),
+                                },
+                            );
                         }
-                    } else if let &Safety::Unsafe(span) = safety {
-                        let mut diag = this
-                            .dcx()
-                            .create_err(errors::UnsafeItem { span, kind: "extern block" });
-                        rustc_session::parse::add_feature_diagnostics(
-                            &mut diag,
-                            self.session,
-                            sym::unsafe_extern_blocks,
-                        );
-                        diag.emit();
                     }
 
                     if abi.is_none() {
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index e99123b9b1c..3ceb8e0711a 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -560,10 +560,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
     gate_all!(global_registration, "global registration is experimental");
     gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");
-    gate_all!(
-        unsafe_extern_blocks,
-        "`unsafe extern {}` blocks and `safe` keyword are experimental"
-    );
     gate_all!(return_type_notation, "return type notation is experimental");
 
     if !visitor.features.never_patterns {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 7a925705806..a58c7c43246 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1124,8 +1124,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     err.multipart_suggestion(
                         "consider moving the expression out of the loop so it is only moved once",
                         vec![
-                            (parent.span, "value".to_string()),
                             (span.shrink_to_lo(), format!("let mut value = {value};{indent}")),
+                            (parent.span, "value".to_string()),
                         ],
                         Applicability::MaybeIncorrect,
                     );
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 8c9de5210cd..1073ea40694 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -225,21 +225,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
                 // Find something that we can name
                 let upper_bound = self.approx_universal_upper_bound(vid);
-                let upper_bound = &self.definitions[upper_bound];
-                match upper_bound.external_name {
-                    Some(reg) => reg,
-                    None => {
-                        // Nothing exact found, so we pick the first one that we find.
-                        let scc = self.constraint_sccs.scc(vid);
-                        for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
-                            match self.definitions[vid].external_name {
-                                None => {}
-                                Some(region) if region.is_static() => {}
-                                Some(region) => return region,
-                            }
-                        }
-                        region
-                    }
+                if let Some(universal_region) = self.definitions[upper_bound].external_name {
+                    return universal_region;
+                }
+
+                // Nothing exact found, so we pick a named upper bound, if there's only one.
+                // If there's >1 universal region, then we probably are dealing w/ an intersection
+                // region which cannot be mapped back to a universal.
+                // FIXME: We could probably compute the LUB if there is one.
+                let scc = self.constraint_sccs.scc(vid);
+                let upper_bounds: Vec<_> = self
+                    .rev_scc_graph
+                    .as_ref()
+                    .unwrap()
+                    .upper_bounds(scc)
+                    .filter_map(|vid| self.definitions[vid].external_name)
+                    .filter(|r| !r.is_static())
+                    .collect();
+                match &upper_bounds[..] {
+                    [universal_region] => *universal_region,
+                    _ => region,
                 }
             }
             _ => region,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index bbb5daccfd6..b13773ffe14 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2330,10 +2330,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         match (cast_ty_from, cast_ty_to) {
                             (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
                                 let mut normalize = |t| self.normalize(t, location);
+
+                                // N.B. `struct_tail_with_normalize` only "structurally resolves"
+                                // the type. It is not fully normalized, so we have to normalize it
+                                // afterwards.
                                 let src_tail =
                                     tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
+                                let src_tail = normalize(src_tail);
                                 let dst_tail =
                                     tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
+                                let dst_tail = normalize(dst_tail);
 
                                 // This checks (lifetime part of) vtable validity for pointer casts,
                                 // which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index ae3cce40f5d..9695df9c87e 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -196,6 +196,9 @@ builtin_macros_format_use_positional = consider using a positional formatting ar
 
 builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
 
+builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
+    .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
+
 builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
     .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
     .suggestion = remove this option
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 09d892768b4..1df2812e0c8 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -80,7 +80,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
     let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
     let decl = cx.fn_decl(params, never);
     let header = FnHeader { safety: Safety::Unsafe(span), ..FnHeader::default() };
-    let sig = FnSig { decl, header, span: span };
+    let sig = FnSig { decl, header, span };
 
     let body = Some(cx.block_expr(call));
     let kind = ItemKind::Fn(Box::new(Fn {
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 06a49dc72b6..17439dd3e3e 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -28,6 +28,29 @@ pub struct AsmArgs {
     pub options_spans: Vec<Span>,
 }
 
+/// Used for better error messages when operand types are used that are not
+/// supported by the current macro (e.g. `in` or `out` for `global_asm!`)
+///
+/// returns
+///
+/// - `Ok(true)` if the current token matches the keyword, and was expected
+/// - `Ok(false)` if the current token does not match the keyword
+/// - `Err(_)` if the current token matches the keyword, but was not expected
+fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> {
+    if expect {
+        Ok(p.eat_keyword(symbol))
+    } else {
+        let span = p.token.span;
+        if p.eat_keyword_noexpect(symbol) {
+            // in gets printed as `r#in` otherwise
+            let symbol = if symbol == kw::In { "in" } else { symbol.as_str() };
+            Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol }))
+        } else {
+            Ok(false)
+        }
+    }
+}
+
 fn parse_args<'a>(
     ecx: &ExtCtxt<'a>,
     sp: Span,
@@ -105,7 +128,7 @@ pub fn parse_asm_args<'a>(
         };
 
         let mut explicit_reg = false;
-        let op = if !is_global_asm && p.eat_keyword(kw::In) {
+        let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -113,15 +136,15 @@ pub fn parse_asm_args<'a>(
             }
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
-        } else if !is_global_asm && p.eat_keyword(sym::out) {
+        } else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
-        } else if !is_global_asm && p.eat_keyword(sym::lateout) {
+        } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
-        } else if !is_global_asm && p.eat_keyword(sym::inout) {
+        } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -135,7 +158,7 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
-        } else if !is_global_asm && p.eat_keyword(sym::inlateout) {
+        } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -149,6 +172,9 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: true }
             }
+        } else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
+            let block = p.parse_block()?;
+            ast::InlineAsmOperand::Label { block }
         } else if p.eat_keyword(kw::Const) {
             let anon_const = p.parse_expr_anon_const()?;
             ast::InlineAsmOperand::Const { anon_const }
@@ -164,9 +190,6 @@ pub fn parse_asm_args<'a>(
                 path: path.clone(),
             };
             ast::InlineAsmOperand::Sym { sym }
-        } else if !is_global_asm && p.eat_keyword(sym::label) {
-            let block = p.parse_block()?;
-            ast::InlineAsmOperand::Label { block }
         } else if allow_templates {
             let template = p.parse_expr()?;
             // If it can't possibly expand to a string, provide diagnostics here to include other
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index dc1874bfecb..4b05c144d37 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -202,7 +202,7 @@ impl CfgEval<'_> {
         }
 
         // Now that we have our re-parsed `AttrTokenStream`, recursively configuring
-        // our attribute target will correctly the tokens as well.
+        // our attribute target will correctly configure the tokens as well.
         flat_map_annotatable(self, annotatable)
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index ba84323a4d0..c8ab8ed681c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -181,11 +181,10 @@ use std::{iter, vec};
 use rustc_ast::ptr::P;
 use rustc_ast::{
     self as ast, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
-    Mutability, PatKind, TyKind, VariantData,
+    Mutability, PatKind, VariantData,
 };
 use rustc_attr as attr;
 use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use thin_vec::{thin_vec, ThinVec};
@@ -1599,52 +1598,11 @@ impl<'a> TraitDef<'a> {
                         ),
                     );
                     if is_packed {
-                        // In general, fields in packed structs are copied via a
-                        // block, e.g. `&{self.0}`. The two exceptions are `[u8]`
-                        // and `str` fields, which cannot be copied and also never
-                        // cause unaligned references. These exceptions are allowed
-                        // to handle the `FlexZeroSlice` type in the `zerovec`
-                        // crate within `icu4x-0.9.0`.
-                        //
-                        // Once use of `icu4x-0.9.0` has dropped sufficiently, this
-                        // exception should be removed.
-                        let is_simple_path = |ty: &P<ast::Ty>, sym| {
-                            if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind
-                                && let [seg] = segments.as_slice()
-                                && seg.ident.name == sym
-                                && seg.args.is_none()
-                            {
-                                true
-                            } else {
-                                false
-                            }
-                        };
-
-                        let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind
-                            && is_simple_path(ty, sym::u8)
-                        {
-                            Some("byte")
-                        } else if is_simple_path(&struct_field.ty, sym::str) {
-                            Some("string")
-                        } else {
-                            None
-                        };
-
-                        if let Some(ty) = exception {
-                            cx.sess.psess.buffer_lint(
-                                BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
-                                sp,
-                                ast::CRATE_NODE_ID,
-                                rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive {
-                                    ty: ty.to_string(),
-                                },
-                            );
-                        } else {
-                            // Wrap the expression in `{...}`, causing a copy.
-                            field_expr = cx.expr_block(
-                                cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]),
-                            );
-                        }
+                        // Fields in packed structs are wrapped in a block, e.g. `&{self.0}`,
+                        // causing a copy instead of a (potentially misaligned) reference.
+                        field_expr = cx.expr_block(
+                            cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]),
+                        );
                     }
                     cx.expr_addr_of(sp, field_expr)
                 })
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 93fc9bcb9d2..6ca43441e05 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -852,6 +852,15 @@ pub(crate) struct GlobalAsmUnsupportedOption {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_global_asm_unsupported_operand)]
+pub(crate) struct GlobalAsmUnsupportedOperand<'a> {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) symbol: &'a str,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_test_runner_invalid)]
 pub(crate) struct TestRunnerInvalid {
     #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 9c70f7ede8c..ff82f0f2da7 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -555,7 +555,7 @@ fn make_format_args(
             };
             let arg_name = args.explicit_args()[index].kind.ident().unwrap();
             ecx.buffered_early_lint.push(BufferedEarlyLint {
-                span: arg_name.span.into(),
+                span: Some(arg_name.span.into()),
                 node_id: rustc_ast::CRATE_NODE_ID,
                 lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
                 diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
index 1ed6f8fc359..30dc5cb1615 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
@@ -2,13 +2,14 @@ name: Abi-cafe
 
 on:
   - push
+  - pull_request
 
 permissions: {}
 
 jobs:
   abi_cafe:
     runs-on: ${{ matrix.os }}
-    timeout-minutes: 60
+    timeout-minutes: 30
     concurrency:
       group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.os }}-${{ matrix.env.TARGET_TRIPLE }}
       cancel-in-progress: true
@@ -27,12 +28,16 @@ jobs:
           - os: macos-latest
             env:
               TARGET_TRIPLE: x86_64-apple-darwin
-          - os: windows-latest
+          - os: macos-latest
             env:
-              TARGET_TRIPLE: x86_64-pc-windows-msvc
+              TARGET_TRIPLE: aarch64-apple-darwin
           - os: windows-latest
             env:
-              TARGET_TRIPLE: x86_64-pc-windows-gnu
+              TARGET_TRIPLE: x86_64-pc-windows-msvc
+          # FIXME Currently hangs. Re-enable once this is fixed or abi-cafe adds a timeout.
+          #- os: windows-latest
+          #  env:
+          #    TARGET_TRIPLE: x86_64-pc-windows-gnu
 
     steps:
     - uses: actions/checkout@v4
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml
index b4f8ce0f532..27c95572ef8 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/audit.yml
@@ -13,7 +13,6 @@ jobs:
       - uses: actions/checkout@v4
       - run: |
           sed -i 's/components.*/components = []/' rust-toolchain
-          echo 'profile = "minimal"' >> rust-toolchain
       - uses: rustsec/audit-check@v1.4.1
         with:
           token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index a2ae3d63fb9..896a5c34c3e 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -29,7 +29,6 @@ jobs:
     - name: Avoid installing rustc-dev
       run: |
         sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain
-        echo 'profile = "minimal"' >> rust-toolchain
         rustfmt -v
 
     - name: Rustfmt
diff --git a/compiler/rustc_codegen_cranelift/.zed/settings.json b/compiler/rustc_codegen_cranelift/.zed/settings.json
new file mode 100644
index 00000000000..e93bed36949
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.zed/settings.json
@@ -0,0 +1,68 @@
+{
+  "format_on_save": "on",
+  "lsp": {
+    "rust-analyzer": {
+      "initialization_options": {
+        "diagnostics": {
+          // in case rustc.source is disabled for performance reasons; disable the errors about this
+          "disabled": ["unresolved-extern-crate", "unresolved-macro-call"]
+        },
+        "rustc": {
+          "source": "discover"
+        },
+        "imports": {
+          "granularity": {
+            "enforce": true,
+            "group": "module"
+          },
+          "prefix": "crate"
+        },
+        "cargo": {
+          "features": ["unstable-features"]
+        },
+        "linkedProjects": [
+          "./Cargo.toml",
+          "./build_system/Cargo.toml",
+          {
+            "crates": [
+              {
+                "root_module": "./example/mini_core.rs",
+                "edition": "2018",
+                "deps": [],
+                "cfg": []
+              },
+              {
+                "root_module": "./example/mini_core_hello_world.rs",
+                "edition": "2018",
+                "deps": [
+                  {
+                    "crate": 0,
+                    "name": "mini_core"
+                  }
+                ],
+                "cfg": []
+              },
+              {
+                "root_module": "./example/mod_bench.rs",
+                "edition": "2018",
+                "deps": [],
+                "cfg": []
+              }
+            ]
+          },
+          {
+            "sysroot_src": "./build/stdlib/library",
+            "crates": [
+              {
+                "root_module": "./example/std_example.rs",
+                "edition": "2015",
+                "deps": [],
+                "cfg": []
+              }
+            ]
+          }
+        ]
+      }
+    }
+  }
+}
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index efec5db836b..02d4d98dc42 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -46,21 +46,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b6b33d7e757a887989eb18b35712b2a67d96171ec3149d1bfb657b29b7b367c"
+checksum = "effa84ab2023f7138045ece6b326588c17447ca22e66db71ec15cb0a6c0c4ad2"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
+name = "cranelift-bitset"
+version = "0.110.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38a1dfc50dca188a15d938867c4400589530bcb0138f7022aae6d059d1d8c309"
+
+[[package]]
 name = "cranelift-codegen"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9acf15cb22be42d07c3b57d7856329cb228b7315d385346149df2566ad5e4aa"
+checksum = "821c20c639350158ecca928dc2a244d0d1c9cef2377a378fc62a445a286eb1ca"
 dependencies = [
  "bumpalo",
  "cranelift-bforest",
+ "cranelift-bitset",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
  "cranelift-control",
@@ -77,39 +84,42 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e934d301392b73b3f8b0540391fb82465a0f179a3cee7c726482ac4727efcc97"
+checksum = "064473f2fd59b44fa2c9aaa60de1f9c44db5e13521e28bc85d2b92ee535ef625"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb2a2566b3d54b854dfb288b3b187f6d3d17d6f762c92898207eba302931da"
+checksum = "d0f39b9ebfd2febdc2acfb9a0fca110665bcd5a6839502576307735ed07b2177"
 
 [[package]]
 name = "cranelift-control"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0100f33b704cdacd01ad66ff41f8c5030d57cbff078e2a4e49ab1822591299fa"
+checksum = "94e125c189c3a1ca8dfe209fc6f46edba058a6d24e0b92aff69459a15f4711e7"
 dependencies = [
  "arbitrary",
 ]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8cfdc315e5d18997093e040a8d234bea1ac1e118a716d3e30f40d449e78207b"
+checksum = "ea62eb109baec2247e1a6fa7b74c0f584b1e76e289cfd7017385b4b031fc8450"
+dependencies = [
+ "cranelift-bitset",
+]
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f74b84f16af2e982b0c0c72233503d9d55cbfe3865dbe807ca28dc6642a28b5"
+checksum = "722b089357aacb6c7528b2e59a5fe00917d61ce63448b25a3e477a5b7819fac8"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -119,15 +129,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adf306d3dde705fb94bd48082f01d38c4ededc74293a4c007805f610bf08bc6e"
+checksum = "c4b5005a48288e7fc2a2991a377831c534e26929b063c379c018060727785a9b"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5c5cfb8bbd3339cd25cca30e7516ff8fe5cb1feeddde6980cc4d5ef34df97bb"
+checksum = "f843932baf8d1025c5f114b929eda172d74b7163d058e0de2597c308b567c7e9"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -145,9 +155,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c9b0d4269b36fd858e6d8f20cd4938941186fb831488c361888cb2d6b33a9a6"
+checksum = "449819ef1c4af139cf1b9717916fcaea0e23248853d3e95135139773a842d3eb"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -156,9 +166,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ea0ebdef7aff4a79bcbc8b6495f31315f16b3bf311152f472eaa8d679352581"
+checksum = "3ae2d48f38081a9e679ad795bd36bb29bedeb5552fc1c195185bf9885fa1b16e"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -167,9 +177,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.109.0"
+version = "0.110.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e33439ec20db058bc7cc3410f9748ab1ad90a35cef713d625c736f43e3820d"
+checksum = "3a39ee2cfd0ec485eca76f6b4dc17701a280fa406bc05137bb43f1635ed12c9f"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -279,9 +289,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "object"
-version = "0.36.1"
+version = "0.36.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
+checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
 dependencies = [
  "crc32fast",
  "hashbrown 0.14.5",
@@ -411,9 +421,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "22.0.0"
+version = "23.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5afe2f0499542f9a4bcfa1b55bfdda803b6ade4e7c93c6b99e0f39dba44b0a91"
+checksum = "7fddf3e2980fb1d123d1fcac55189e417fdd3dba4f62139b5a0a1f9efe5669d5"
 dependencies = [
  "anyhow",
  "cfg-if",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 2969a6cf6ec..a0df502dadc 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,12 +8,12 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.109.0", default-features = false, features = ["std", "unwind", "all-arch"] }
-cranelift-frontend = { version = "0.109.0" }
-cranelift-module = { version = "0.109.0" }
-cranelift-native = { version = "0.109.0" }
-cranelift-jit = { version = "0.109.0", optional = true }
-cranelift-object = { version = "0.109.0" }
+cranelift-codegen = { version = "0.110.1", default-features = false, features = ["std", "unwind", "all-arch"] }
+cranelift-frontend = { version = "0.110.1" }
+cranelift-module = { version = "0.110.1" }
+cranelift-native = { version = "0.110.1" }
+cranelift-jit = { version = "0.110.1", optional = true }
+cranelift-object = { version = "0.110.1" }
 target-lexicon = "0.12.0"
 gimli = { version = "0.28", default-features = false, features = ["write"]}
 object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index 3b3c86a1bd1..6766e2f844d 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -16,7 +16,6 @@ $ rustup component add rustc-codegen-cranelift-preview --toolchain nightly
 
 Once it is installed, you can enable it with one of the following approaches:
 - `CARGO_PROFILE_DEV_CODEGEN_BACKEND=cranelift cargo +nightly build -Zcodegen-backend`
-- `RUSTFLAGS="-Zcodegen-backend=cranelift" cargo +nightly build`
 - Add the following to `.cargo/config.toml`:
     ```toml
     [unstable]
diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
index 75f9f233cb3..e3f1162445b 100644
--- a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
@@ -1,4 +1,4 @@
-use crate::path::Dirs;
+use crate::path::{Dirs, RelPath};
 use crate::prepare::GitRepo;
 use crate::utils::{spawn_and_wait, CargoProject, Compiler};
 use crate::{build_sysroot, CodegenBackend, SysrootKind};
@@ -6,8 +6,8 @@ use crate::{build_sysroot, CodegenBackend, SysrootKind};
 static ABI_CAFE_REPO: GitRepo = GitRepo::github(
     "Gankra",
     "abi-cafe",
-    "4c6dc8c9c687e2b3a760ff2176ce236872b37212",
-    "588df6d66abbe105",
+    "f1220cfd13b57f5c0082c26529163865ee25e115",
+    "fe93a9acd461425d",
     "abi-cafe",
 );
 
@@ -21,6 +21,7 @@ pub(crate) fn run(
     rustup_toolchain_name: Option<&str>,
     bootstrap_host_compiler: &Compiler,
 ) {
+    RelPath::DOWNLOAD.ensure_exists(dirs);
     ABI_CAFE_REPO.fetch(dirs);
     ABI_CAFE_REPO.patch(dirs);
 
@@ -38,17 +39,23 @@ pub(crate) fn run(
     eprintln!("Running abi-cafe");
 
     let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
-
-    let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
-    cmd.arg("--");
-    cmd.arg("--pairs");
-    cmd.args(
+    let pairs =
         if cfg!(not(any(target_os = "macos", all(target_os = "windows", target_env = "msvc")))) {
             &pairs[..]
         } else {
             &pairs[..2]
-        },
-    );
+        };
+
+    let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
+    cmd.arg("--");
+
+    // stdcall, vectorcall and such don't work yet
+    cmd.arg("--conventions").arg("c").arg("--conventions").arg("rust");
+
+    for pair in pairs {
+        cmd.arg("--pairs").arg(pair);
+    }
+
     cmd.arg("--add-rustc-codegen-backend");
     match cg_clif_dylib {
         CodegenBackend::Local(path) => {
@@ -58,6 +65,7 @@ pub(crate) fn run(
             cmd.arg(format!("cgclif:{name}"));
         }
     }
+
     cmd.current_dir(ABI_CAFE.source_dir(dirs));
 
     spawn_and_wait(cmd);
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index ed8b5b906d2..e41f6c5e709 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -312,7 +312,6 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
         let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o"));
         let mut build_rtstartup_cmd = Command::new(&compiler.rustc);
         build_rtstartup_cmd
-            .arg("-Ainternal_features") // Missing #[allow(internal_features)]
             .arg("--target")
             .arg(&compiler.triple)
             .arg("--emit=obj")
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index 5525a5f63e9..be0bed0f4e6 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -22,36 +22,6 @@ pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) {
     assert!(sysroot_src_orig.exists());
 
     apply_patches(dirs, "stdlib", &sysroot_src_orig, &STDLIB_SRC.to_path(dirs));
-
-    std::fs::write(
-        STDLIB_SRC.to_path(dirs).join("Cargo.toml"),
-        r#"
-[workspace]
-resolver = "1"
-members = ["./library/sysroot"]
-
-[patch.crates-io]
-rustc-std-workspace-core = { path = "./library/rustc-std-workspace-core" }
-rustc-std-workspace-alloc = { path = "./library/rustc-std-workspace-alloc" }
-rustc-std-workspace-std = { path = "./library/rustc-std-workspace-std" }
-
-# Mandatory for correctly compiling compiler-builtins
-[profile.dev.package.compiler_builtins]
-debug-assertions = false
-overflow-checks = false
-codegen-units = 10000
-
-[profile.release.package.compiler_builtins]
-debug-assertions = false
-overflow-checks = false
-codegen-units = 10000
-"#,
-    )
-    .unwrap();
-
-    let source_lockfile = RelPath::PATCHES.to_path(dirs).join("stdlib-lock.toml");
-    let target_lockfile = STDLIB_SRC.to_path(dirs).join("Cargo.lock");
-    fs::copy(source_lockfile, target_lockfile).unwrap();
 }
 
 pub(crate) struct GitRepo {
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index afc8a923863..38c3786a94a 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -106,6 +106,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
         ]);
         runner.run_out_command("gen_block_iterate", &[]);
     }),
+    TestCase::build_bin_and_run("aot.raw-dylib", "example/raw-dylib.rs", &[]),
 ];
 
 pub(crate) static RAND_REPO: GitRepo = GitRepo::github(
@@ -437,7 +438,7 @@ impl<'a> TestRunner<'a> {
         cmd.arg("-L");
         cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
         cmd.arg("--out-dir");
-        cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
+        cmd.arg(BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs));
         cmd.arg("-Cdebuginfo=2");
         cmd.arg("--target");
         cmd.arg(&self.target_compiler.triple);
diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt
index 0b7cac18837..527ec5303b6 100644
--- a/compiler/rustc_codegen_cranelift/config.txt
+++ b/compiler/rustc_codegen_cranelift/config.txt
@@ -45,6 +45,7 @@ aot.issue-59326
 aot.polymorphize_coroutine
 aot.neon
 aot.gen_block_iterate
+aot.raw-dylib
 
 testsuite.extended_sysroot
 test.rust-random/rand
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 7d361a9ab2b..e603ac566f4 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -585,6 +585,7 @@ pub enum E2<X> {
     V4,
 }
 
+#[allow(unreachable_patterns)]
 fn check_niche_behavior() {
     if let E1::V2 { .. } = (E1::V1 { f: true }) {
         intrinsics::abort();
diff --git a/compiler/rustc_codegen_cranelift/example/raw-dylib.rs b/compiler/rustc_codegen_cranelift/example/raw-dylib.rs
new file mode 100644
index 00000000000..4711884f76a
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/example/raw-dylib.rs
@@ -0,0 +1,31 @@
+// Tests the raw-dylib feature for Windows.
+// https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute
+
+fn main() {
+    #[cfg(windows)]
+    {
+        #[link(name = "kernel32", kind = "raw-dylib")]
+        extern "C" {
+            fn GetModuleFileNameA(
+                module: *mut std::ffi::c_void,
+                filename: *mut u8,
+                size: u32,
+            ) -> u32;
+        }
+
+        // Get the filename of the current executable....
+        let mut buffer = [0u8; 1024];
+        let size = unsafe {
+            GetModuleFileNameA(core::ptr::null_mut(), buffer.as_mut_ptr(), buffer.len() as u32)
+        };
+        if size == 0 {
+            eprintln!("failed to get module file name: {}", std::io::Error::last_os_error());
+            return;
+        } else {
+            // ...and make sure that it matches the test name.
+            let filename =
+                std::ffi::CStr::from_bytes_with_nul(&buffer[..size as usize + 1]).unwrap();
+            assert!(filename.to_str().unwrap().ends_with("raw-dylib.exe"));
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch
deleted file mode 100644
index 77716c51399..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 2b15fee2bb5fd14e34c7e17e44d99cb34f4c555d Mon Sep 17 00:00:00 2001
-From: Afonso Bordado <afonsobordado@az8.co>
-Date: Tue, 27 Sep 2022 07:55:17 +0100
-Subject: [PATCH] Disable some test on x86_64-pc-windows-gnu
-
----
- src/report.rs | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/src/report.rs b/src/report.rs
-index eeec614..f582867 100644
---- a/src/report.rs
-+++ b/src/report.rs
-@@ -48,6 +48,15 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
-     //
-     // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
- 
-+    // x86_64-pc-windows-gnu has some broken i128 tests that aren't disabled by default
-+    if cfg!(all(target_os = "windows", target_env = "gnu")) && test.test_name == "ui128" {
-+        result.run = Link;
-+        result.check = Pass(Link);
-+    } else if test.test_name == "ui128" {
-+        result.run == Check;
-+        result.check = Pass(Check);
-+    }
-+
-     // END OF VENDOR RESERVED AREA
-     //
-     //
--- 
-2.30.1.windows.1
-
diff --git a/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch b/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch
new file mode 100644
index 00000000000..8a2565f1668
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch
@@ -0,0 +1,75 @@
+From 236df390f3bc4ed69c26f4d51d584bea246da886 Mon Sep 17 00:00:00 2001
+From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
+Date: Tue, 9 Jul 2024 11:25:14 +0000
+Subject: [PATCH] Disable broken tests
+
+---
+ src/report.rs | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/src/report.rs b/src/report.rs
+index 958ab43..dcf1044 100644
+--- a/src/report.rs
++++ b/src/report.rs
+@@ -48,6 +48,58 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn Toolchain, callee: &dyn Toolc
+     //
+     // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
+ 
++    if cfg!(all(target_arch = "aarch64", target_os = "linux")) {
++        if test.test == "F32Array" && test.options.convention == CallingConvention::C {
++            result.check = Busted(Check);
++        }
++
++        if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
++            result.check = Busted(Check);
++        }
++    }
++
++    if cfg!(all(target_arch = "aarch64", target_os = "macos")) {
++        if test.test == "SingleVariantUnion" && test.options.convention == CallingConvention::C && test.options.repr == LangRepr::C {
++            result.check = Busted(Check);
++        }
++
++        if test.test == "OptionU128" && test.caller == "rustc" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
++            result.check = Busted(Run);
++        }
++
++        if test.test == "OptionU128" && test.caller == "cgclif" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
++            result.check = Busted(Check);
++        }
++    }
++
++    if cfg!(all(target_arch = "x86_64", unix)) {
++        if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::Rust {
++            result.check = Busted(Run);
++        }
++    }
++
++    if cfg!(all(target_arch = "x86_64", windows)) {
++        if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust {
++            result.check = Busted(Check);
++        }
++
++        if test.test == "OptionU128" && test.options.convention == CallingConvention::Rust && (test.caller == "rustc" || test.options.repr == LangRepr::Rust) {
++            result.check = Busted(Run);
++        }
++
++        if test.test == "simple" && test.options.convention == CallingConvention::Rust {
++            result.check = Busted(Check);
++        }
++
++        if test.test == "simple" && test.options.convention == CallingConvention::Rust && test.caller == "rustc" {
++            result.check = Busted(Run);
++        }
++    }
++
++    if test.test == "f16" || test.test == "f128" {
++        result.run = Skip;
++    }
++
+     // END OF VENDOR RESERVED AREA
+     //
+     //
+-- 
+2.34.1
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
index 7cf7f86700e..8c404956bcc 100644
--- a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
@@ -37,8 +37,8 @@ index 42a26ae..5ac1042 100644
 +++ b/lib.rs
 @@ -1,3 +1,4 @@
 +#![cfg(test)]
- #![feature(alloc_layout_extra)]
- #![feature(array_chunks)]
- #![feature(array_ptr_get)]
+ // tidy-alphabetical-start
+ #![cfg_attr(bootstrap, feature(offset_of_nested))]
+ #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
 --
 2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
index 271ca12eabb..d579c9588f0 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
@@ -11,17 +11,17 @@ Cranelift doesn't support them yet
  4 files changed, 4 insertions(+), 50 deletions(-)
 
 diff --git a/lib.rs b/lib.rs
-index 897a5e9..331f66f 100644
+index 1e336bf..35e6f54 100644
 --- a/lib.rs
 +++ b/lib.rs
-@@ -93,7 +93,6 @@
- #![feature(const_option)]
- #![feature(const_option_ext)]
- #![feature(const_result)]
+@@ -1,7 +1,6 @@
+ #![cfg(test)]
+ // tidy-alphabetical-start
+ #![cfg_attr(bootstrap, feature(offset_of_nested))]
 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
  #![cfg_attr(test, feature(cfg_match))]
- #![feature(int_roundings)]
- #![feature(split_array)]
+ #![feature(alloc_layout_extra)]
+ #![feature(array_chunks)]
 diff --git a/atomic.rs b/atomic.rs
 index b735957..ea728b6 100644
 --- a/atomic.rs
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
new file mode 100644
index 00000000000..ada35145e29
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
@@ -0,0 +1,25 @@
+From 175d52c5e1779764b66777db1e6f172c2dc365ff Mon Sep 17 00:00:00 2001
+From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
+Date: Fri, 9 Aug 2024 15:44:51 +0000
+Subject: [PATCH] Disable f16 and f128 in compiler-builtins
+
+---
+ library/sysroot/Cargo.toml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
+index 7165c3e48af..968552ad435 100644
+--- a/library/sysroot/Cargo.toml
++++ b/library/sysroot/Cargo.toml
+@@ -11,7 +11,7 @@ test = { path = "../test" }
+ 
+ # Forward features to the `std` crate as necessary
+ [features]
+-default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
++default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind", "compiler-builtins-no-f16-f128"]
+ backtrace = ["std/backtrace"]
+ compiler-builtins-c = ["std/compiler-builtins-c"]
+ compiler-builtins-mem = ["std/compiler-builtins-mem"]
+-- 
+2.34.1
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch
deleted file mode 100644
index 584dbdb647f..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 9f65e742ba3e41474e6126c6c4469c48eaa6ca7e Mon Sep 17 00:00:00 2001
-From: Chris Denton <chris@chrisdenton.dev>
-Date: Tue, 20 Feb 2024 16:01:40 -0300
-Subject: [PATCH] Don't use raw-dylib in std
-
----
- library/std/src/sys/pal/windows/c.rs    | 2 +-
- library/std/src/sys/pal/windows/rand.rs | 3 +--
- 2 files changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
-index ad8e01bfa9b..9ca8e4c16ce 100644
---- a/library/std/src/sys/pal/windows/c.rs
-+++ b/library/std/src/sys/pal/windows/c.rs
-@@ -312,7 +312,7 @@ pub unsafe fn NtWriteFile(
- 
- // Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
- cfg_if::cfg_if! {
--if #[cfg(not(target_vendor = "win7"))] {
-+if #[cfg(any())] {
-     #[cfg(target_arch = "x86")]
-     #[link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")]
-     extern "system" {
-diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs
-index e427546222a..f2fe42a4d51 100644
---- a/library/std/src/sys/pal/windows/rand.rs
-+++ b/library/std/src/sys/pal/windows/rand.rs
-@@ -2,7 +2,7 @@
- 
- use crate::sys::c;
- 
--#[cfg(not(target_vendor = "win7"))]
-+#[cfg(any())]
- #[inline]
- pub fn hashmap_random_keys() -> (u64, u64) {
-     let mut v = (0, 0);
-@@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) {
-     v
- }
- 
--#[cfg(target_vendor = "win7")]
- pub fn hashmap_random_keys() -> (u64, u64) {
-     use crate::ffi::c_void;
-     use crate::io;
--- 
-2.42.0.windows.2
-
diff --git a/compiler/rustc_codegen_cranelift/patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch b/compiler/rustc_codegen_cranelift/patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch
deleted file mode 100644
index 21f5ee9cc6e..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 0d741cf82c3c908616abd39dc84ebf7d8702e0c3 Mon Sep 17 00:00:00 2001
-From: Chris Denton <chris@chrisdenton.dev>
-Date: Tue, 16 Apr 2024 15:51:34 +0000
-Subject: [PATCH] Revert use raw-dylib for Windows futex APIs
-
----
- library/std/src/sys/pal/windows/c.rs | 14 +-------------
- 1 file changed, 1 insertion(+), 13 deletions(-)
-
-diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
-index 9d58ce05f01..1c828bac4b6 100644
---- a/library/std/src/sys/pal/windows/c.rs
-+++ b/library/std/src/sys/pal/windows/c.rs
-@@ -357,19 +357,7 @@ pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
- }
- 
- #[cfg(not(target_vendor = "win7"))]
--// Use raw-dylib to import synchronization functions to workaround issues with the older mingw import library.
--#[cfg_attr(
--    target_arch = "x86",
--    link(
--        name = "api-ms-win-core-synch-l1-2-0",
--        kind = "raw-dylib",
--        import_name_type = "undecorated"
--    )
--)]
--#[cfg_attr(
--    not(target_arch = "x86"),
--    link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib")
--)]
-+#[link(name = "synchronization")]
- extern "system" {
-     pub fn WaitOnAddress(
-         address: *const c_void,
--- 
-2.42.0.windows.2
-
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index db9b551bd2a..96c467e091c 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,4 @@
 [toolchain]
-channel = "nightly-2024-07-13"
+channel = "nightly-2024-08-09"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
+profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index f0550c23b17..bb5af9127b9 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -39,6 +39,7 @@ rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.r
 # exotic linkages
 rm tests/incremental/hashes/function_interfaces.rs
 rm tests/incremental/hashes/statics.rs
+rm -r tests/run-make/naked-symbol-visibility
 
 # variadic arguments
 rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs
@@ -118,6 +119,7 @@ rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 rm tests/ui/mir/mir_raw_fat_ptr.rs # same
 rm tests/ui/consts/issue-33537.rs # same
 rm tests/ui/consts/const-mut-refs-crate.rs # same
+rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift
 
 # doesn't work due to the way the rustc test suite is invoked.
 # should work when using ./x.py test the way it is intended
@@ -134,6 +136,8 @@ rm tests/ui/deprecation/deprecated_inline_threshold.rs # missing deprecation war
 # bugs in the test suite
 # ======================
 rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
+rm tests/ui/backtrace/synchronized-panic-handler.rs # missing needs-unwind annotation
+rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables
 
 rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
 
@@ -157,8 +161,8 @@ index ea06b620c4c..b969d0009c6 100644
  RUSTDOC := \$(RUSTDOC) -Clinker='\$(RUSTC_LINKER)'
 diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
 index 9607ff02f96..b7d97caf9a2 100644
---- a/src/tools/run-make-support/src/rustdoc.rs
-+++ b/src/tools/run-make-support/src/rustdoc.rs
+--- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
++++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
 @@ -34,8 +34,6 @@ pub fn bare() -> Self {
      #[track_caller]
      pub fn new() -> Self {
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index 1935005a08c..5eedab4f2cb 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -1,8 +1,13 @@
-use std::path::{Path, PathBuf};
+use std::borrow::Borrow;
+use std::fs;
+use std::path::Path;
 
+use ar_archive_writer::{COFFShortExport, MachineTypes};
 use rustc_codegen_ssa::back::archive::{
-    ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
+    create_mingw_dll_import_lib, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
+    DEFAULT_OBJECT_READER,
 };
+use rustc_codegen_ssa::common::is_mingw_gnu_toolchain;
 use rustc_session::Session;
 
 pub(crate) struct ArArchiveBuilderBuilder;
@@ -15,11 +20,74 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
     fn create_dll_import_lib(
         &self,
         sess: &Session,
-        _lib_name: &str,
-        _dll_imports: &[rustc_session::cstore::DllImport],
-        _tmpdir: &Path,
-        _is_direct_dependency: bool,
-    ) -> PathBuf {
-        sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift");
+        lib_name: &str,
+        import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+        output_path: &Path,
+    ) {
+        if is_mingw_gnu_toolchain(&sess.target) {
+            // The binutils linker used on -windows-gnu targets cannot read the import
+            // libraries generated by LLVM: in our attempts, the linker produced an .EXE
+            // that loaded but crashed with an AV upon calling one of the imported
+            // functions. Therefore, use binutils to create the import library instead,
+            // by writing a .DEF file to the temp dir and calling binutils's dlltool.
+            create_mingw_dll_import_lib(
+                sess,
+                lib_name,
+                import_name_and_ordinal_vector,
+                output_path,
+            );
+        } else {
+            let mut file =
+                match fs::OpenOptions::new().write(true).create_new(true).open(&output_path) {
+                    Ok(file) => file,
+                    Err(error) => {
+                        sess.dcx().fatal(format!(
+                            "failed to create import library file `{path}`: {error}",
+                            path = output_path.display(),
+                        ));
+                    }
+                };
+
+            let machine = match sess.target.arch.borrow() {
+                "x86" => MachineTypes::I386,
+                "x86_64" => MachineTypes::AMD64,
+                "arm" => MachineTypes::ARMNT,
+                "aarch64" => MachineTypes::ARM64,
+                _ => {
+                    sess.dcx().fatal(format!(
+                        "unsupported target architecture `{arch}`",
+                        arch = sess.target.arch,
+                    ));
+                }
+            };
+
+            let exports = import_name_and_ordinal_vector
+                .iter()
+                .map(|(name, ordinal)| COFFShortExport {
+                    name: name.to_string(),
+                    ext_name: None,
+                    symbol_name: None,
+                    alias_target: None,
+                    ordinal: ordinal.unwrap_or(0),
+                    noname: ordinal.is_some(),
+                    data: false,
+                    private: false,
+                    constant: false,
+                })
+                .collect::<Vec<_>>();
+
+            if let Err(error) = ar_archive_writer::write_import_library(
+                &mut file,
+                lib_name,
+                &exports,
+                machine,
+                !sess.target.is_like_msvc,
+            ) {
+                sess.dcx().fatal(format!(
+                    "failed to create import library `{path}`: `{error}`",
+                    path = output_path.display(),
+                ));
+            }
+        }
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index e16b77648d1..b6a4769e031 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -23,19 +23,7 @@ pub(crate) fn maybe_codegen<'tcx>(
     match bin_op {
         BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => None,
         BinOp::Add | BinOp::AddUnchecked | BinOp::Sub | BinOp::SubUnchecked => None,
-        BinOp::Mul | BinOp::MulUnchecked => {
-            let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
-            let ret_val = fx.lib_call(
-                "__multi3",
-                vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
-                vec![AbiParam::new(types::I128)],
-                &args,
-            )[0];
-            Some(CValue::by_val(
-                ret_val,
-                fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }),
-            ))
-        }
+        BinOp::Mul | BinOp::MulUnchecked => None,
         BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
         BinOp::Div | BinOp::Rem => {
             let name = match (bin_op, is_signed) {
@@ -92,6 +80,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
 
     match bin_op {
         BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
+        BinOp::Add | BinOp::Sub => None,
         BinOp::Mul if is_signed => {
             let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
             let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
@@ -112,7 +101,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
             let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
             Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
         }
-        BinOp::Add | BinOp::Sub | BinOp::Mul => {
+        BinOp::Mul => {
             let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
             let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
             let param_types = vec![
@@ -121,15 +110,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
                 AbiParam::new(types::I128),
             ];
             let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
-            let name = match (bin_op, is_signed) {
-                (BinOp::Add, false) => "__rust_u128_addo",
-                (BinOp::Add, true) => "__rust_i128_addo",
-                (BinOp::Sub, false) => "__rust_u128_subo",
-                (BinOp::Sub, true) => "__rust_i128_subo",
-                (BinOp::Mul, false) => "__rust_u128_mulo",
-                _ => unreachable!(),
-            };
-            fx.lib_call(name, param_types, vec![], &args);
+            fx.lib_call("__rust_u128_mulo", param_types, vec![], &args);
             Some(out_place.to_cvalue(fx))
         }
         BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 09317139936..a1b29a42225 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -107,7 +107,7 @@ pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         return false;
     }
 
-    let tail = tcx.struct_tail_erasing_lifetimes(ty, ParamEnv::reveal_all());
+    let tail = tcx.struct_tail_for_codegen(ty, ParamEnv::reveal_all());
     match tail.kind() {
         ty::Foreign(..) => false,
         ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
diff --git a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
index f3b963200a0..4154a62234c 100644
--- a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
+++ b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
@@ -38,18 +38,12 @@ builtin_functions! {
     register_functions_for_jit;
 
     // integers
-    fn __multi3(a: i128, b: i128) -> i128;
     fn __muloti4(n: i128, d: i128, oflow: &mut i32) -> i128;
     fn __udivti3(n: u128, d: u128) -> u128;
     fn __divti3(n: i128, d: i128) -> i128;
     fn __umodti3(n: u128, d: u128) -> u128;
     fn __modti3(n: i128, d: i128) -> i128;
-    fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool);
-    fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool);
-    fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool);
-    fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool);
     fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool);
-    fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool);
 
     // floats
     fn __floattisf(i: i128) -> f32;
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index a20faa2cad3..cb003037c26 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -169,39 +169,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             }
         }
 
-        "llvm.x86.sse.add.ss" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_add_ss&ig_expand=171
-            intrinsic_args!(fx, args => (a, b); intrinsic);
-
-            assert_eq!(a.layout(), b.layout());
-            assert_eq!(a.layout(), ret.layout());
-            let layout = a.layout();
-
-            let (_, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            assert!(lane_ty.is_floating_point());
-            let ret_lane_layout = fx.layout_of(lane_ty);
-
-            ret.write_cvalue(fx, a);
-
-            let a_lane = a.value_lane(fx, 0).load_scalar(fx);
-            let b_lane = b.value_lane(fx, 0).load_scalar(fx);
-
-            let res = fx.bcx.ins().fadd(a_lane, b_lane);
-
-            let res_lane = CValue::by_val(res, ret_lane_layout);
-            ret.place_lane(fx, 0).write_cvalue(fx, res_lane);
-        }
-
-        "llvm.x86.sse.sqrt.ps" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sqrt_ps&ig_expand=6245
-            intrinsic_args!(fx, args => (a); intrinsic);
-
-            // FIXME use vector instructions when possible
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
-                fx.bcx.ins().sqrt(lane)
-            });
-        }
-
         "llvm.x86.sse.max.ps" => {
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_ps&ig_expand=4357
             intrinsic_args!(fx, args => (a, b); intrinsic);
@@ -744,117 +711,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             pack_instruction(fx, a, b, ret, PackSize::S16, PackWidth::Avx);
         }
 
-        "llvm.x86.fma.vfmaddsub.ps"
-        | "llvm.x86.fma.vfmaddsub.pd"
-        | "llvm.x86.fma.vfmaddsub.ps.256"
-        | "llvm.x86.fma.vfmaddsub.pd.256" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmaddsub_ps&ig_expand=3205
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmaddsub_pd&ig_expand=3181
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmaddsub_ps&ig_expand=3209
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmaddsub_pd&ig_expand=3185
-            intrinsic_args!(fx, args => (a, b, c); intrinsic);
-
-            assert_eq!(a.layout(), b.layout());
-            assert_eq!(a.layout(), c.layout());
-            let layout = a.layout();
-
-            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
-            assert!(lane_ty.is_floating_point());
-            assert!(ret_lane_ty.is_floating_point());
-            assert_eq!(lane_count, ret_lane_count);
-            let ret_lane_layout = fx.layout_of(ret_lane_ty);
-
-            for idx in 0..lane_count {
-                let a_lane = a.value_lane(fx, idx).load_scalar(fx);
-                let b_lane = b.value_lane(fx, idx).load_scalar(fx);
-                let c_lane = c.value_lane(fx, idx).load_scalar(fx);
-
-                let mul = fx.bcx.ins().fmul(a_lane, b_lane);
-                let res = if idx & 1 == 0 {
-                    fx.bcx.ins().fsub(mul, c_lane)
-                } else {
-                    fx.bcx.ins().fadd(mul, c_lane)
-                };
-
-                let res_lane = CValue::by_val(res, ret_lane_layout);
-                ret.place_lane(fx, idx).write_cvalue(fx, res_lane);
-            }
-        }
-
-        "llvm.x86.fma.vfmsubadd.ps"
-        | "llvm.x86.fma.vfmsubadd.pd"
-        | "llvm.x86.fma.vfmsubadd.ps.256"
-        | "llvm.x86.fma.vfmsubadd.pd.256" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmsubadd_ps&ig_expand=3325
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmsubadd_pd&ig_expand=3301
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmsubadd_ps&ig_expand=3329
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmsubadd_pd&ig_expand=3305
-            intrinsic_args!(fx, args => (a, b, c); intrinsic);
-
-            assert_eq!(a.layout(), b.layout());
-            assert_eq!(a.layout(), c.layout());
-            let layout = a.layout();
-
-            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
-            assert!(lane_ty.is_floating_point());
-            assert!(ret_lane_ty.is_floating_point());
-            assert_eq!(lane_count, ret_lane_count);
-            let ret_lane_layout = fx.layout_of(ret_lane_ty);
-
-            for idx in 0..lane_count {
-                let a_lane = a.value_lane(fx, idx).load_scalar(fx);
-                let b_lane = b.value_lane(fx, idx).load_scalar(fx);
-                let c_lane = c.value_lane(fx, idx).load_scalar(fx);
-
-                let mul = fx.bcx.ins().fmul(a_lane, b_lane);
-                let res = if idx & 1 == 0 {
-                    fx.bcx.ins().fadd(mul, c_lane)
-                } else {
-                    fx.bcx.ins().fsub(mul, c_lane)
-                };
-
-                let res_lane = CValue::by_val(res, ret_lane_layout);
-                ret.place_lane(fx, idx).write_cvalue(fx, res_lane);
-            }
-        }
-
-        "llvm.x86.fma.vfnmadd.ps"
-        | "llvm.x86.fma.vfnmadd.pd"
-        | "llvm.x86.fma.vfnmadd.ps.256"
-        | "llvm.x86.fma.vfnmadd.pd.256" => {
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fnmadd_ps&ig_expand=3391
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fnmadd_pd&ig_expand=3367
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fnmadd_ps&ig_expand=3395
-            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fnmadd_pd&ig_expand=3371
-            intrinsic_args!(fx, args => (a, b, c); intrinsic);
-
-            assert_eq!(a.layout(), b.layout());
-            assert_eq!(a.layout(), c.layout());
-            let layout = a.layout();
-
-            let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
-            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
-            assert!(lane_ty.is_floating_point());
-            assert!(ret_lane_ty.is_floating_point());
-            assert_eq!(lane_count, ret_lane_count);
-            let ret_lane_layout = fx.layout_of(ret_lane_ty);
-
-            for idx in 0..lane_count {
-                let a_lane = a.value_lane(fx, idx).load_scalar(fx);
-                let b_lane = b.value_lane(fx, idx).load_scalar(fx);
-                let c_lane = c.value_lane(fx, idx).load_scalar(fx);
-
-                let mul = fx.bcx.ins().fmul(a_lane, b_lane);
-                let neg_mul = fx.bcx.ins().fneg(mul);
-                let res = fx.bcx.ins().fadd(neg_mul, c_lane);
-
-                let res_lane = CValue::by_val(res, ret_lane_layout);
-                ret.place_lane(fx, idx).write_cvalue(fx, res_lane);
-            }
-        }
-
         "llvm.x86.sse42.crc32.32.8"
         | "llvm.x86.sse42.crc32.32.16"
         | "llvm.x86.sse42.crc32.32.32"
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 9d46d8d6dac..21930fa2ddb 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -12,6 +12,7 @@
 #![warn(unused_lifetimes)]
 // tidy-alphabetical-end
 
+extern crate ar_archive_writer;
 extern crate jobserver;
 #[macro_use]
 extern crate rustc_middle;
@@ -190,9 +191,20 @@ impl CodegenBackend for CraneliftCodegenBackend {
         if sess.target.arch == "x86_64" && sess.target.os != "none" {
             // x86_64 mandates SSE2 support
             vec![Symbol::intern("fxsr"), sym::sse, Symbol::intern("sse2")]
-        } else if sess.target.arch == "aarch64" && sess.target.os != "none" {
-            // AArch64 mandates Neon support
-            vec![sym::neon]
+        } else if sess.target.arch == "aarch64" {
+            match &*sess.target.os {
+                "none" => vec![],
+                // On macOS the aes, sha2 and sha3 features are enabled by default and ring
+                // fails to compile on macOS when they are not present.
+                "macos" => vec![
+                    sym::neon,
+                    Symbol::intern("aes"),
+                    Symbol::intern("sha2"),
+                    Symbol::intern("sha3"),
+                ],
+                // AArch64 mandates Neon support
+                _ => vec![sym::neon],
+            }
         } else {
             vec![]
         }
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 967aa53abbd..e09cd16e89a 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -22,7 +22,7 @@ pub(crate) fn unsized_info<'tcx>(
     old_info: Option<Value>,
 ) -> Value {
     let (source, target) =
-        fx.tcx.struct_lockstep_tails_erasing_lifetimes(source, target, ParamEnv::reveal_all());
+        fx.tcx.struct_lockstep_tails_for_codegen(source, target, ParamEnv::reveal_all());
     match (&source.kind(), &target.kind()) {
         (&ty::Array(_, len), &ty::Slice(_)) => fx
             .bcx
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 1aa28daeafc..8eb2095e523 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -677,8 +677,10 @@ impl<'tcx> CPlace<'tcx> {
                         let to_addr = to_ptr.get_addr(fx);
                         let src_layout = from.1;
                         let size = dst_layout.size.bytes();
-                        let src_align = src_layout.align.abi.bytes() as u8;
-                        let dst_align = dst_layout.align.abi.bytes() as u8;
+                        // `emit_small_memory_copy` uses `u8` for alignments, just use the maximum
+                        // alignment that fits in a `u8` if the actual alignment is larger.
+                        let src_align = src_layout.align.abi.bytes().try_into().unwrap_or(128);
+                        let dst_align = dst_layout.align.abi.bytes().try_into().unwrap_or(128);
                         fx.bcx.emit_small_memory_copy(
                             fx.target_config,
                             to_addr,
diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock
index d6ec1f87d01..771f2f18dce 100644
--- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock
@@ -50,7 +50,7 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.109"
+version = "0.1.118"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f11973008a8cf741fe6d22f339eba21fd0ca81e2760a769ba8243ed6c21edd7e"
 dependencies = [
diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml
index e4669923623..05503128f2a 100644
--- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml
@@ -6,9 +6,7 @@ resolver = "2"
 
 [dependencies]
 core = { path = "./sysroot_src/library/core" }
-# TODO: after the sync, revert to using version 0.1.
-# compiler_builtins = "0.1"
-compiler_builtins = "=0.1.109"
+compiler_builtins = "0.1"
 alloc = { path = "./sysroot_src/library/alloc" }
 std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
 test = { path = "./sysroot_src/library/test" }
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 5a7ddc4cd7f..9f096e90220 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -430,6 +430,7 @@ pub enum E2<X> {
     V4,
 }
 
+#[allow(unreachable_patterns)]
 fn check_niche_behavior () {
     if let E1::V2 { .. } = (E1::V1 { f: true }) {
         intrinsics::abort();
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
index 36f5e0f8094..0cee05f1cea 100644
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -1,9 +1,8 @@
-use std::path::{Path, PathBuf};
+use std::path::Path;
 
 use rustc_codegen_ssa::back::archive::{
     ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
 };
-use rustc_session::cstore::DllImport;
 use rustc_session::Session;
 
 pub(crate) struct ArArchiveBuilderBuilder;
@@ -17,10 +16,9 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
         &self,
         _sess: &Session,
         _lib_name: &str,
-        _dll_imports: &[DllImport],
-        _tmpdir: &Path,
-        _is_direct_dependency: bool,
-    ) -> PathBuf {
+        _import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+        _output_path: &Path,
+    ) {
         unimplemented!("creating dll imports is not yet supported");
     }
 }
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index e521551304e..5fdf2680aac 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -75,7 +75,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
     let function_features = codegen_fn_attrs
         .target_features
         .iter()
-        .map(|features| features.as_str())
+        .map(|features| features.name.as_str())
         .collect::<Vec<&str>>();
 
     if let Some(features) = check_tied_features(
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 8bb90efe6fb..5308ccdb614 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -65,8 +65,8 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
 
             let feature = backend_feature_name(s)?;
             // Warn against use of GCC specific feature names on the CLI.
-            if diagnostics && !supported_features.iter().any(|&(v, _)| v == feature) {
-                let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| {
+            if diagnostics && !supported_features.iter().any(|&(v, _, _)| v == feature) {
+                let rust_feature = supported_features.iter().find_map(|&(rust_feature, _, _)| {
                     let gcc_features = to_gcc_features(sess, rust_feature);
                     if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) {
                         Some(rust_feature)
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index cd63a405b67..94f016234f9 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -486,7 +486,7 @@ pub fn target_features(
     sess.target
         .supported_target_features()
         .iter()
-        .filter_map(|&(feature, gate)| {
+        .filter_map(|&(feature, gate, _)| {
             if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
                 Some(feature)
             } else {
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index 1c126e79762..267da9325c3 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -1,23 +1,13 @@
 codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
 
-codegen_llvm_dlltool_fail_import_library =
-    Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
-    {$stdout}
-    {$stderr}
-
 codegen_llvm_dynamic_linking_with_lto =
     cannot prefer dynamic linking when performing LTO
     .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
 
-codegen_llvm_error_calling_dlltool =
-    Error calling dlltool '{$dlltool_path}': {$error}
 
 codegen_llvm_error_creating_import_library =
     Error creating import library for {$lib_name}: {$error}
 
-codegen_llvm_error_writing_def_file =
-    Error writing .DEF file: {$error}
-
 codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
 
 codegen_llvm_from_llvm_diag = {$message}
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index b8f42031263..1277b7898c2 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -5,10 +5,10 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::MemFlags;
-use rustc_middle::bug;
 use rustc_middle::ty::layout::LayoutOf;
 pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
 use rustc_middle::ty::Ty;
+use rustc_middle::{bug, ty};
 use rustc_session::config;
 pub use rustc_target::abi::call::*;
 use rustc_target::abi::{self, HasDataLayout, Int, Size};
@@ -16,6 +16,7 @@ pub use rustc_target::spec::abi::Abi;
 use rustc_target::spec::SanitizerSet;
 use smallvec::SmallVec;
 
+use crate::attributes::llfn_attrs_from_instance;
 use crate::builder::Builder;
 use crate::context::CodegenCx;
 use crate::llvm::{self, Attribute, AttributePlace};
@@ -310,7 +311,16 @@ pub trait FnAbiLlvmExt<'ll, 'tcx> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn llvm_cconv(&self) -> llvm::CallConv;
-    fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
+
+    /// Apply attributes to a function declaration/definition.
+    fn apply_attrs_llfn(
+        &self,
+        cx: &CodegenCx<'ll, 'tcx>,
+        llfn: &'ll Value,
+        instance: Option<ty::Instance<'tcx>>,
+    );
+
+    /// Apply attributes to a function call.
     fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value);
 }
 
@@ -396,7 +406,12 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         self.conv.into()
     }
 
-    fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
+    fn apply_attrs_llfn(
+        &self,
+        cx: &CodegenCx<'ll, 'tcx>,
+        llfn: &'ll Value,
+        instance: Option<ty::Instance<'tcx>>,
+    ) {
         let mut func_attrs = SmallVec::<[_; 3]>::new();
         if self.ret.layout.abi.is_uninhabited() {
             func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
@@ -477,6 +492,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                 }
             }
         }
+
+        // If the declaration has an associated instance, compute extra attributes based on that.
+        if let Some(instance) = instance {
+            llfn_attrs_from_instance(cx, llfn, instance);
+        }
     }
 
     fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index ad38814a68b..fde95104093 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -324,9 +324,10 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
     llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
 }
 
+/// Helper for `FnAbi::apply_attrs_llfn`:
 /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
 /// attributes.
-pub fn from_fn_attrs<'ll, 'tcx>(
+pub fn llfn_attrs_from_instance<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     llfn: &'ll Value,
     instance: ty::Instance<'tcx>,
@@ -496,7 +497,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     to_add.extend(tune_cpu_attr(cx));
 
     let function_features =
-        codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
+        codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
 
     if let Some(f) = llvm_util::check_tied_features(
         cx.tcx.sess,
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 2f5a864d70e..a2ab19ac800 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -1,21 +1,19 @@
 //! A helper class for dealing with static archives
 
-use std::ffi::{c_char, c_void, CStr, CString, OsString};
+use std::ffi::{c_char, c_void, CStr, CString};
 use std::path::{Path, PathBuf};
-use std::{env, io, mem, ptr, str};
+use std::{io, mem, ptr, str};
 
 use rustc_codegen_ssa::back::archive::{
-    try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
-    ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER,
+    create_mingw_dll_import_lib, try_extract_macho_fat_archive, ArArchiveBuilder,
+    ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind,
+    DEFAULT_OBJECT_READER,
 };
-use rustc_session::cstore::DllImport;
+use rustc_codegen_ssa::common;
 use rustc_session::Session;
 use tracing::trace;
 
-use crate::common;
-use crate::errors::{
-    DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
-};
+use crate::errors::ErrorCreatingImportLibrary;
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 
@@ -121,116 +119,21 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
         &self,
         sess: &Session,
         lib_name: &str,
-        dll_imports: &[DllImport],
-        tmpdir: &Path,
-        is_direct_dependency: bool,
-    ) -> PathBuf {
-        let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
-        let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib"));
-
-        let target = &sess.target;
-        let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);
-
-        let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
-            .iter()
-            .map(|import: &DllImport| {
-                if sess.target.arch == "x86" {
-                    (
-                        common::i686_decorated_name(import, mingw_gnu_toolchain, false),
-                        import.ordinal(),
-                    )
-                } else {
-                    (import.name.to_string(), import.ordinal())
-                }
-            })
-            .collect();
-
-        if mingw_gnu_toolchain {
+        import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+        output_path: &Path,
+    ) {
+        if common::is_mingw_gnu_toolchain(&sess.target) {
             // The binutils linker used on -windows-gnu targets cannot read the import
             // libraries generated by LLVM: in our attempts, the linker produced an .EXE
             // that loaded but crashed with an AV upon calling one of the imported
             // functions. Therefore, use binutils to create the import library instead,
             // by writing a .DEF file to the temp dir and calling binutils's dlltool.
-            let def_file_path = tmpdir.join(format!("{lib_name}{name_suffix}.def"));
-
-            let def_file_content = format!(
-                "EXPORTS\n{}",
-                import_name_and_ordinal_vector
-                    .into_iter()
-                    .map(|(name, ordinal)| {
-                        match ordinal {
-                            Some(n) => format!("{name} @{n} NONAME"),
-                            None => name,
-                        }
-                    })
-                    .collect::<Vec<String>>()
-                    .join("\n")
+            create_mingw_dll_import_lib(
+                sess,
+                lib_name,
+                import_name_and_ordinal_vector,
+                output_path,
             );
-
-            match std::fs::write(&def_file_path, def_file_content) {
-                Ok(_) => {}
-                Err(e) => {
-                    sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
-                }
-            };
-
-            // --no-leading-underscore: For the `import_name_type` feature to work, we need to be
-            // able to control the *exact* spelling of each of the symbols that are being imported:
-            // hence we don't want `dlltool` adding leading underscores automatically.
-            let dlltool = find_binutils_dlltool(sess);
-            let temp_prefix = {
-                let mut path = PathBuf::from(&output_path);
-                path.pop();
-                path.push(lib_name);
-                path
-            };
-            // dlltool target architecture args from:
-            // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
-            let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
-                "x86_64" => ("i386:x86-64", "--64"),
-                "x86" => ("i386", "--32"),
-                "aarch64" => ("arm64", "--64"),
-                "arm" => ("arm", "--32"),
-                _ => panic!("unsupported arch {}", sess.target.arch),
-            };
-            let mut dlltool_cmd = std::process::Command::new(&dlltool);
-            dlltool_cmd
-                .arg("-d")
-                .arg(def_file_path)
-                .arg("-D")
-                .arg(lib_name)
-                .arg("-l")
-                .arg(&output_path)
-                .arg("-m")
-                .arg(dlltool_target_arch)
-                .arg("-f")
-                .arg(dlltool_target_bitness)
-                .arg("--no-leading-underscore")
-                .arg("--temp-prefix")
-                .arg(temp_prefix);
-
-            match dlltool_cmd.output() {
-                Err(e) => {
-                    sess.dcx().emit_fatal(ErrorCallingDllTool {
-                        dlltool_path: dlltool.to_string_lossy(),
-                        error: e,
-                    });
-                }
-                // dlltool returns '0' on failure, so check for error output instead.
-                Ok(output) if !output.stderr.is_empty() => {
-                    sess.dcx().emit_fatal(DlltoolFailImportLibrary {
-                        dlltool_path: dlltool.to_string_lossy(),
-                        dlltool_args: dlltool_cmd
-                            .get_args()
-                            .map(|arg| arg.to_string_lossy())
-                            .collect::<Vec<_>>()
-                            .join(" "),
-                        stdout: String::from_utf8_lossy(&output.stdout),
-                        stderr: String::from_utf8_lossy(&output.stderr),
-                    })
-                }
-                _ => {}
-            }
         } else {
             // we've checked for \0 characters in the library name already
             let dll_name_z = CString::new(lib_name).unwrap();
@@ -242,9 +145,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
             trace!("  output_path {}", output_path.display());
             trace!(
                 "  import names: {}",
-                dll_imports
+                import_name_and_ordinal_vector
                     .iter()
-                    .map(|import| import.name.to_string())
+                    .map(|(name, _ordinal)| name.clone())
                     .collect::<Vec<_>>()
                     .join(", "),
             );
@@ -281,9 +184,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                     error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
                 });
             }
-        };
-
-        output_path
+        }
     }
 }
 
@@ -457,39 +358,3 @@ impl<'a> LlvmArchiveBuilder<'a> {
 fn string_to_io_error(s: String) -> io::Error {
     io::Error::new(io::ErrorKind::Other, format!("bad archive: {s}"))
 }
-
-fn find_binutils_dlltool(sess: &Session) -> OsString {
-    assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
-    if let Some(dlltool_path) = &sess.opts.cg.dlltool {
-        return dlltool_path.clone().into_os_string();
-    }
-
-    let tool_name: OsString = if sess.host.options.is_like_windows {
-        // If we're compiling on Windows, always use "dlltool.exe".
-        "dlltool.exe"
-    } else {
-        // On other platforms, use the architecture-specific name.
-        match sess.target.arch.as_ref() {
-            "x86_64" => "x86_64-w64-mingw32-dlltool",
-            "x86" => "i686-w64-mingw32-dlltool",
-            "aarch64" => "aarch64-w64-mingw32-dlltool",
-
-            // For non-standard architectures (e.g., aarch32) fallback to "dlltool".
-            _ => "dlltool",
-        }
-    }
-    .into();
-
-    // NOTE: it's not clear how useful it is to explicitly search PATH.
-    for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
-        let full_path = dir.join(&tool_name);
-        if full_path.is_file() {
-            return full_path.into_os_string();
-        }
-    }
-
-    // The user didn't specify the location of the dlltool binary, and we weren't able
-    // to find the appropriate one on the PATH. Just return the name of the tool
-    // and let the invocation fail with a hopefully useful error message.
-    tool_name
-}
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 5a7909d1511..a1f2433ab6f 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -95,11 +95,14 @@ pub fn write_output_file<'ll>(
     }
 }
 
-pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
+pub fn create_informational_target_machine(
+    sess: &Session,
+    only_base_features: bool,
+) -> OwnedTargetMachine {
     let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
     // Can't use query system here quite yet because this function is invoked before the query
     // system/tcx is set up.
-    let features = llvm_util::global_llvm_features(sess, false);
+    let features = llvm_util::global_llvm_features(sess, false, only_base_features);
     target_machine_factory(sess, config::OptLevel::No, &features)(config)
         .unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise())
 }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 77e51f94150..0f44c5dba5e 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -12,7 +12,8 @@ use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::layout::{
-    FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
+    TyAndLayout,
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_sanitizers::{cfi, kcfi};
@@ -531,7 +532,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     #[instrument(level = "trace", skip(self))]
     fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> {
         if place.layout.is_unsized() {
-            let tail = self.tcx.struct_tail_with_normalize(place.layout.ty, |ty| ty, || {});
+            let tail = self.tcx.struct_tail_for_codegen(place.layout.ty, self.param_env());
             if matches!(tail.kind(), ty::Foreign(..)) {
                 // Unsized locals and, at least conceptually, even unsized arguments must be copied
                 // around, which requires dynamically determining their size. Therefore, we cannot
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index c913bdebaaa..663c5be46e5 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -4,13 +4,14 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
+use rustc_codegen_ssa::common;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, TypeVisitableExt};
 use tracing::debug;
 
 use crate::context::CodegenCx;
+use crate::llvm;
 use crate::value::Value;
-use crate::{attributes, common, llvm};
 
 /// Codegens a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
@@ -46,7 +47,7 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
     } else {
         let instance_def_id = instance.def_id();
         let llfn = if tcx.sess.target.arch == "x86"
-            && let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym)
+            && let Some(dllimport) = crate::common::get_dllimport(tcx, instance_def_id, sym)
         {
             // Fix for https://github.com/rust-lang/rust/issues/104453
             // On x86 Windows, LLVM uses 'L' as the prefix for any private
@@ -77,8 +78,6 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
         };
         debug!("get_fn: not casting pointer!");
 
-        attributes::from_fn_attrs(cx, llfn, instance);
-
         // Apply an appropriate linkage/visibility value to our item that we
         // just declared.
         //
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 197bbb9ddbf..65f974c5689 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -1,7 +1,5 @@
 //! Code that is useful in various codegen modules.
 
-use std::fmt::Write;
-
 use libc::{c_char, c_uint};
 use rustc_ast::Mutability;
 use rustc_codegen_ssa::traits::*;
@@ -10,9 +8,8 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
+use rustc_session::cstore::DllImport;
 use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer};
-use rustc_target::spec::Target;
 use tracing::debug;
 
 use crate::consts::const_alloc_to_llvm;
@@ -379,64 +376,3 @@ pub(crate) fn get_dllimport<'tcx>(
     tcx.native_library(id)
         .and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name))
 }
-
-pub(crate) fn is_mingw_gnu_toolchain(target: &Target) -> bool {
-    target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
-}
-
-pub(crate) fn i686_decorated_name(
-    dll_import: &DllImport,
-    mingw: bool,
-    disable_name_mangling: bool,
-) -> String {
-    let name = dll_import.name.as_str();
-
-    let (add_prefix, add_suffix) = match dll_import.import_name_type {
-        Some(PeImportNameType::NoPrefix) => (false, true),
-        Some(PeImportNameType::Undecorated) => (false, false),
-        _ => (true, true),
-    };
-
-    // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
-    let mut decorated_name = String::with_capacity(name.len() + 6);
-
-    if disable_name_mangling {
-        // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled.
-        decorated_name.push('\x01');
-    }
-
-    let prefix = if add_prefix && dll_import.is_fn {
-        match dll_import.calling_convention {
-            DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
-            DllCallingConvention::Stdcall(_) => (!mingw
-                || dll_import.import_name_type == Some(PeImportNameType::Decorated))
-            .then_some('_'),
-            DllCallingConvention::Fastcall(_) => Some('@'),
-        }
-    } else if !dll_import.is_fn && !mingw {
-        // For static variables, prefix with '_' on MSVC.
-        Some('_')
-    } else {
-        None
-    };
-    if let Some(prefix) = prefix {
-        decorated_name.push(prefix);
-    }
-
-    decorated_name.push_str(name);
-
-    if add_suffix && dll_import.is_fn {
-        match dll_import.calling_convention {
-            DllCallingConvention::C => {}
-            DllCallingConvention::Stdcall(arg_list_size)
-            | DllCallingConvention::Fastcall(arg_list_size) => {
-                write!(&mut decorated_name, "@{arg_list_size}").unwrap();
-            }
-            DllCallingConvention::Vectorcall(arg_list_size) => {
-                write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
-            }
-        }
-    }
-
-    decorated_name
-}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index c3ea4a18a71..75b298f14ca 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -1,5 +1,6 @@
 use std::ops::Range;
 
+use rustc_codegen_ssa::common;
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -18,7 +19,7 @@ use rustc_target::abi::{
 };
 use tracing::{debug, instrument, trace};
 
-use crate::common::{self, CodegenCx};
+use crate::common::CodegenCx;
 use crate::errors::{
     InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined,
 };
@@ -195,7 +196,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             g2
         }
     } else if cx.tcx.sess.target.arch == "x86"
-        && let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym)
+        && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
     {
         cx.declare_global(
             &common::i686_decorated_name(
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index ea930421b58..dd3f39ecead 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -149,7 +149,7 @@ pub unsafe fn create_module<'ll>(
 
     // Ensure the data-layout values hardcoded remain the defaults.
     {
-        let tm = crate::back::write::create_informational_target_machine(tcx.sess);
+        let tm = crate::back::write::create_informational_target_machine(tcx.sess, false);
         unsafe {
             llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
         }
@@ -775,10 +775,10 @@ impl<'ll> CodegenCx<'ll, '_> {
         ifn!("llvm.debugtrap", fn() -> void);
         ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
 
-        ifn!("llvm.powi.f16", fn(t_f16, t_i32) -> t_f16);
-        ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
-        ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
-        ifn!("llvm.powi.f128", fn(t_f128, t_i32) -> t_f128);
+        ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16);
+        ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32);
+        ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64);
+        ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128);
 
         ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16);
         ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index d51e15d12e2..e542aa96e8a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -62,7 +62,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     pointee_ty: Ty<'tcx>,
 ) -> Option<FatPtrKind> {
-    let pointee_tail_ty = cx.tcx.struct_tail_erasing_lifetimes(pointee_ty, cx.param_env());
+    let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env());
     let layout = cx.layout_of(pointee_tail_ty);
     trace!(
         "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index c4887464e19..2aa349b2782 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -137,7 +137,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             llvm::Visibility::Default,
             fn_abi.llvm_type(self),
         );
-        fn_abi.apply_attrs_llfn(self, llfn);
+        fn_abi.apply_attrs_llfn(self, llfn, instance);
 
         if self.tcx.sess.is_sanitizer_cfi_enabled() {
             if let Some(instance) = instance {
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index a3957bc52a5..7e53d32ce8c 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -1,4 +1,3 @@
-use std::borrow::Cow;
 use std::ffi::CString;
 use std::path::Path;
 
@@ -72,28 +71,6 @@ pub(crate) struct InvalidMinimumAlignmentTooLarge {
 pub(crate) struct SanitizerMemtagRequiresMte;
 
 #[derive(Diagnostic)]
-#[diag(codegen_llvm_error_writing_def_file)]
-pub(crate) struct ErrorWritingDEFFile {
-    pub error: std::io::Error,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_error_calling_dlltool)]
-pub(crate) struct ErrorCallingDllTool<'a> {
-    pub dlltool_path: Cow<'a, str>,
-    pub error: std::io::Error,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_dlltool_fail_import_library)]
-pub(crate) struct DlltoolFailImportLibrary<'a> {
-    pub dlltool_path: Cow<'a, str>,
-    pub dlltool_args: String,
-    pub stdout: Cow<'a, str>,
-    pub stderr: Cow<'a, str>,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_llvm_dynamic_linking_with_lto)]
 #[note]
 pub(crate) struct DynamicLinkingWithLTO;
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 040de1c7dd7..57d5f6fdf50 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -35,10 +35,10 @@ fn get_simple_intrinsic<'ll>(
         sym::sqrtf64 => "llvm.sqrt.f64",
         sym::sqrtf128 => "llvm.sqrt.f128",
 
-        sym::powif16 => "llvm.powi.f16",
-        sym::powif32 => "llvm.powi.f32",
-        sym::powif64 => "llvm.powi.f64",
-        sym::powif128 => "llvm.powi.f128",
+        sym::powif16 => "llvm.powi.f16.i32",
+        sym::powif32 => "llvm.powi.f32.i32",
+        sym::powif64 => "llvm.powi.f64.i32",
+        sym::powif128 => "llvm.powi.f128.i32",
 
         sym::sinf16 => "llvm.sin.f16",
         sym::sinf32 => "llvm.sin.f32",
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 41e9cfd1066..518a86e0cb0 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -269,7 +269,7 @@ impl CodegenBackend for LlvmCodegenBackend {
 
     fn provide(&self, providers: &mut Providers) {
         providers.global_backend_features =
-            |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true)
+            |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true, false)
     }
 
     fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
@@ -434,7 +434,7 @@ impl ModuleLlvm {
             ModuleLlvm {
                 llmod_raw,
                 llcx,
-                tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),
+                tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)),
             }
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index dc21b92a95f..9fd8ca43789 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -8,6 +8,7 @@ use libc::c_int;
 use rustc_codegen_ssa::base::wants_wasm_eh;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_data_structures::unord::UnordSet;
 use rustc_fs_util::path_to_c_string;
 use rustc_middle::bug;
 use rustc_session::config::{PrintKind, PrintRequest};
@@ -239,40 +240,8 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
         }
         // In LLVM neon implicitly enables fp, but we manually enable
         // neon when a feature only implicitly enables fp
-        ("aarch64", "f32mm") => {
-            LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "f64mm") => {
-            LLVMFeature::with_dependency("f64mm", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "fhm") => {
-            LLVMFeature::with_dependency("fp16fml", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "fp16") => {
-            LLVMFeature::with_dependency("fullfp16", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "jsconv") => {
-            LLVMFeature::with_dependency("jsconv", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve") => {
-            LLVMFeature::with_dependency("sve", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2") => {
-            LLVMFeature::with_dependency("sve2", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2-aes") => {
-            LLVMFeature::with_dependency("sve2-aes", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2-sm4") => {
-            LLVMFeature::with_dependency("sve2-sm4", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2-sha3") => {
-            LLVMFeature::with_dependency("sve2-sha3", TargetFeatureFoldStrength::EnableOnly("neon"))
-        }
-        ("aarch64", "sve2-bitperm") => LLVMFeature::with_dependency(
-            "sve2-bitperm",
-            TargetFeatureFoldStrength::EnableOnly("neon"),
-        ),
+        ("aarch64", "fhm") => LLVMFeature::new("fp16fml"),
+        ("aarch64", "fp16") => LLVMFeature::new("fullfp16"),
         // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
         // `fast-unaligned-access`. In LLVM 19, it was split back out.
         ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
@@ -308,11 +277,53 @@ pub fn check_tied_features(
 /// Used to generate cfg variables and apply features
 /// Must express features in the way Rust understands them
 pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
-    let target_machine = create_informational_target_machine(sess);
+    let mut features = vec![];
+
+    // Add base features for the target
+    let target_machine = create_informational_target_machine(sess, true);
+    features.extend(
+        sess.target
+            .supported_target_features()
+            .iter()
+            .filter(|(feature, _, _)| {
+                // skip checking special features, as LLVM may not understands them
+                if RUSTC_SPECIAL_FEATURES.contains(feature) {
+                    return true;
+                }
+                // check that all features in a given smallvec are enabled
+                for llvm_feature in to_llvm_features(sess, feature) {
+                    let cstr = SmallCStr::new(llvm_feature);
+                    if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
+                        return false;
+                    }
+                }
+                true
+            })
+            .map(|(feature, _, _)| Symbol::intern(feature)),
+    );
+
+    // Add enabled features
+    for (enabled, feature) in
+        sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() {
+            Some('+') => Some((true, Symbol::intern(&s[1..]))),
+            Some('-') => Some((false, Symbol::intern(&s[1..]))),
+            _ => None,
+        })
+    {
+        if enabled {
+            features.extend(sess.target.implied_target_features(std::iter::once(feature)));
+        } else {
+            features.retain(|f| {
+                !sess.target.implied_target_features(std::iter::once(*f)).contains(&feature)
+            });
+        }
+    }
+
+    // Filter enabled features based on feature gates
     sess.target
         .supported_target_features()
         .iter()
-        .filter_map(|&(feature, gate)| {
+        .filter_map(|&(feature, gate, _)| {
             if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
                 Some(feature)
             } else {
@@ -320,18 +331,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
             }
         })
         .filter(|feature| {
-            // skip checking special features, as LLVM may not understands them
-            if RUSTC_SPECIAL_FEATURES.contains(feature) {
-                return true;
-            }
-            // check that all features in a given smallvec are enabled
-            for llvm_feature in to_llvm_features(sess, feature) {
-                let cstr = SmallCStr::new(llvm_feature);
-                if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
-                    return false;
-                }
-            }
-            true
+            RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature))
         })
         .map(|feature| Symbol::intern(feature))
         .collect()
@@ -386,7 +386,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
         .target
         .supported_target_features()
         .iter()
-        .map(|(feature, _gate)| {
+        .map(|(feature, _gate, _implied)| {
             // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
             let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name;
             let desc =
@@ -440,7 +440,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
 
 pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
     require_inited();
-    let tm = create_informational_target_machine(sess);
+    let tm = create_informational_target_machine(sess, false);
     match req.kind {
         PrintKind::TargetCPUs => {
             // SAFETY generate a C compatible string from a byte slice to pass
@@ -488,7 +488,11 @@ pub fn target_cpu(sess: &Session) -> &str {
 
 /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
 /// `--target` and similar).
-pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<String> {
+pub(crate) fn global_llvm_features(
+    sess: &Session,
+    diagnostics: bool,
+    only_base_features: bool,
+) -> Vec<String> {
     // Features that come earlier are overridden by conflicting features later in the string.
     // Typically we'll want more explicit settings to override the implicit ones, so:
     //
@@ -548,94 +552,124 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
     }
 
     // -Ctarget-features
-    let supported_features = sess.target.supported_target_features();
-    let (llvm_major, _, _) = get_version();
-    let mut featsmap = FxHashMap::default();
-    let feats = sess
-        .opts
-        .cg
-        .target_feature
-        .split(',')
-        .filter_map(|s| {
-            let enable_disable = match s.chars().next() {
-                None => return None,
-                Some(c @ ('+' | '-')) => c,
-                Some(_) => {
-                    if diagnostics {
-                        sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
+    if !only_base_features {
+        let supported_features = sess.target.supported_target_features();
+        let (llvm_major, _, _) = get_version();
+        let mut featsmap = FxHashMap::default();
+
+        // insert implied features
+        let mut all_rust_features = vec![];
+        for feature in sess.opts.cg.target_feature.split(',') {
+            match feature.strip_prefix('+') {
+                Some(feature) => all_rust_features.extend(
+                    UnordSet::from(
+                        sess.target
+                            .implied_target_features(std::iter::once(Symbol::intern(feature))),
+                    )
+                    .to_sorted_stable_ord()
+                    .iter()
+                    .map(|s| format!("+{}", s.as_str())),
+                ),
+                _ => all_rust_features.push(feature.to_string()),
+            }
+        }
+
+        let feats = all_rust_features
+            .iter()
+            .filter_map(|s| {
+                let enable_disable = match s.chars().next() {
+                    None => return None,
+                    Some(c @ ('+' | '-')) => c,
+                    Some(_) => {
+                        if diagnostics {
+                            sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
+                        }
+                        return None;
                     }
-                    return None;
-                }
-            };
+                };
 
-            let feature = backend_feature_name(sess, s)?;
-            // Warn against use of LLVM specific feature names and unstable features on the CLI.
-            if diagnostics {
-                let feature_state = supported_features.iter().find(|&&(v, _)| v == feature);
-                if feature_state.is_none() {
-                    let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| {
-                        let llvm_features = to_llvm_features(sess, rust_feature);
-                        if llvm_features.contains(feature) && !llvm_features.contains(rust_feature)
-                        {
-                            Some(rust_feature)
+                let feature = backend_feature_name(sess, s)?;
+                // Warn against use of LLVM specific feature names and unstable features on the CLI.
+                if diagnostics {
+                    let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
+                    if feature_state.is_none() {
+                        let rust_feature =
+                            supported_features.iter().find_map(|&(rust_feature, _, _)| {
+                                let llvm_features = to_llvm_features(sess, rust_feature);
+                                if llvm_features.contains(feature)
+                                    && !llvm_features.contains(rust_feature)
+                                {
+                                    Some(rust_feature)
+                                } else {
+                                    None
+                                }
+                            });
+                        let unknown_feature = if let Some(rust_feature) = rust_feature {
+                            UnknownCTargetFeature {
+                                feature,
+                                rust_feature: PossibleFeature::Some { rust_feature },
+                            }
                         } else {
-                            None
-                        }
-                    });
-                    let unknown_feature = if let Some(rust_feature) = rust_feature {
-                        UnknownCTargetFeature {
-                            feature,
-                            rust_feature: PossibleFeature::Some { rust_feature },
-                        }
-                    } else {
-                        UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
-                    };
-                    sess.dcx().emit_warn(unknown_feature);
-                } else if feature_state
-                    .is_some_and(|(_name, feature_gate)| !feature_gate.is_stable())
-                {
-                    // An unstable feature. Warn about using it.
-                    sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+                            UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+                        };
+                        sess.dcx().emit_warn(unknown_feature);
+                    } else if feature_state
+                        .is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
+                    {
+                        // An unstable feature. Warn about using it.
+                        sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+                    }
                 }
-            }
 
-            if diagnostics {
-                // FIXME(nagisa): figure out how to not allocate a full hashset here.
-                featsmap.insert(feature, enable_disable == '+');
-            }
+                if diagnostics {
+                    // FIXME(nagisa): figure out how to not allocate a full hashset here.
+                    featsmap.insert(feature, enable_disable == '+');
+                }
 
-            // rustc-specific features do not get passed down to LLVM…
-            if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
-                return None;
-            }
+                // rustc-specific features do not get passed down to LLVM…
+                if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+                    return None;
+                }
 
-            // if the target-feature is "backchain" and LLVM version is greater than 18
-            // then we also need to add "+backchain" to the target-features attribute.
-            // otherwise, we will only add the naked `backchain` attribute to the attribute-group.
-            if feature == "backchain" && llvm_major < 18 {
-                return None;
-            }
-            // ... otherwise though we run through `to_llvm_features` when
-            // passing requests down to LLVM. This means that all in-language
-            // features also work on the command line instead of having two
-            // different names when the LLVM name and the Rust name differ.
-            let llvm_feature = to_llvm_features(sess, feature);
-
-            Some(
-                std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name))
-                    .chain(llvm_feature.dependency.into_iter().filter_map(move |feat| {
-                        match (enable_disable, feat) {
+                // if the target-feature is "backchain" and LLVM version is greater than 18
+                // then we also need to add "+backchain" to the target-features attribute.
+                // otherwise, we will only add the naked `backchain` attribute to the attribute-group.
+                if feature == "backchain" && llvm_major < 18 {
+                    return None;
+                }
+                // ... otherwise though we run through `to_llvm_features` when
+                // passing requests down to LLVM. This means that all in-language
+                // features also work on the command line instead of having two
+                // different names when the LLVM name and the Rust name differ.
+                let llvm_feature = to_llvm_features(sess, feature);
+
+                Some(
+                    std::iter::once(format!(
+                        "{}{}",
+                        enable_disable, llvm_feature.llvm_feature_name
+                    ))
+                    .chain(llvm_feature.dependency.into_iter().filter_map(
+                        move |feat| match (enable_disable, feat) {
                             ('-' | '+', TargetFeatureFoldStrength::Both(f))
                             | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
                                 Some(format!("{enable_disable}{f}"))
                             }
                             _ => None,
-                        }
-                    })),
-            )
-        })
-        .flatten();
-    features.extend(feats);
+                        },
+                    )),
+                )
+            })
+            .flatten();
+        features.extend(feats);
+
+        if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
+            sess.dcx().emit_err(TargetFeatureDisableOrEnable {
+                features: f,
+                span: None,
+                missing_features: None,
+            });
+        }
+    }
 
     // -Zfixed-x18
     if sess.opts.unstable_opts.fixed_x18 {
@@ -646,14 +680,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
         }
     }
 
-    if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
-        sess.dcx().emit_err(TargetFeatureDisableOrEnable {
-            features: f,
-            span: None,
-            missing_features: None,
-        });
-    }
-
     features
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index d59eaae1ba9..f1ef359594b 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -12,7 +12,7 @@ use tracing::debug;
 use crate::context::CodegenCx;
 use crate::errors::SymbolAlreadyDefined;
 use crate::type_of::LayoutLlvmExt;
-use crate::{attributes, base, llvm};
+use crate::{base, llvm};
 
 impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
     fn predefine_static(
@@ -87,8 +87,6 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
 
         debug!("predefine_fn: instance = {:?}", instance);
 
-        attributes::from_fn_attrs(self, lldecl, instance);
-
         unsafe {
             if self.should_assume_dso_local(lldecl, false) {
                 llvm::LLVMRustSetDSOLocal(lldecl, true);
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 2767ad5ec9c..6e1c323cbd0 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-ar_archive_writer = "0.3.0"
+ar_archive_writer = "0.3.3"
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
 cc = "1.0.90"
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 57d789aef80..80f25d42a08 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -24,8 +24,19 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e
 
 codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
 
+codegen_ssa_dlltool_fail_import_library =
+    Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
+    {$stdout}
+    {$stderr}
+
+codegen_ssa_error_calling_dlltool =
+    Error calling dlltool '{$dlltool_path}': {$error}
+
 codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
 
+codegen_ssa_error_writing_def_file =
+    Error writing .DEF file: {$error}
+
 codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 4f93b7b23c6..ce55d99f506 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -1,4 +1,6 @@
+use std::env;
 use std::error::Error;
+use std::ffi::OsString;
 use std::fs::{self, File};
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
@@ -9,7 +11,6 @@ use object::read::archive::ArchiveFile;
 use object::read::macho::FatArch;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::memmap::Mmap;
-use rustc_session::cstore::DllImport;
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 use tempfile::Builder as TempFileBuilder;
@@ -17,6 +18,7 @@ use tempfile::Builder as TempFileBuilder;
 use super::metadata::search_for_section;
 // Re-exporting for rustc_codegen_llvm::back::archive
 pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
+use crate::errors::{DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorWritingDEFFile};
 
 pub trait ArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
@@ -30,10 +32,9 @@ pub trait ArchiveBuilderBuilder {
         &self,
         sess: &Session,
         lib_name: &str,
-        dll_imports: &[DllImport],
-        tmpdir: &Path,
-        is_direct_dependency: bool,
-    ) -> PathBuf;
+        import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+        output_path: &Path,
+    );
 
     fn extract_bundled_libs<'a>(
         &'a self,
@@ -72,6 +73,130 @@ pub trait ArchiveBuilderBuilder {
     }
 }
 
+pub fn create_mingw_dll_import_lib(
+    sess: &Session,
+    lib_name: &str,
+    import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
+    output_path: &Path,
+) {
+    let def_file_path = output_path.with_extension("def");
+
+    let def_file_content = format!(
+        "EXPORTS\n{}",
+        import_name_and_ordinal_vector
+            .into_iter()
+            .map(|(name, ordinal)| {
+                match ordinal {
+                    Some(n) => format!("{name} @{n} NONAME"),
+                    None => name,
+                }
+            })
+            .collect::<Vec<String>>()
+            .join("\n")
+    );
+
+    match std::fs::write(&def_file_path, def_file_content) {
+        Ok(_) => {}
+        Err(e) => {
+            sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
+        }
+    };
+
+    // --no-leading-underscore: For the `import_name_type` feature to work, we need to be
+    // able to control the *exact* spelling of each of the symbols that are being imported:
+    // hence we don't want `dlltool` adding leading underscores automatically.
+    let dlltool = find_binutils_dlltool(sess);
+    let temp_prefix = {
+        let mut path = PathBuf::from(&output_path);
+        path.pop();
+        path.push(lib_name);
+        path
+    };
+    // dlltool target architecture args from:
+    // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
+    let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
+        "x86_64" => ("i386:x86-64", "--64"),
+        "x86" => ("i386", "--32"),
+        "aarch64" => ("arm64", "--64"),
+        "arm" => ("arm", "--32"),
+        _ => panic!("unsupported arch {}", sess.target.arch),
+    };
+    let mut dlltool_cmd = std::process::Command::new(&dlltool);
+    dlltool_cmd
+        .arg("-d")
+        .arg(def_file_path)
+        .arg("-D")
+        .arg(lib_name)
+        .arg("-l")
+        .arg(&output_path)
+        .arg("-m")
+        .arg(dlltool_target_arch)
+        .arg("-f")
+        .arg(dlltool_target_bitness)
+        .arg("--no-leading-underscore")
+        .arg("--temp-prefix")
+        .arg(temp_prefix);
+
+    match dlltool_cmd.output() {
+        Err(e) => {
+            sess.dcx().emit_fatal(ErrorCallingDllTool {
+                dlltool_path: dlltool.to_string_lossy(),
+                error: e,
+            });
+        }
+        // dlltool returns '0' on failure, so check for error output instead.
+        Ok(output) if !output.stderr.is_empty() => {
+            sess.dcx().emit_fatal(DlltoolFailImportLibrary {
+                dlltool_path: dlltool.to_string_lossy(),
+                dlltool_args: dlltool_cmd
+                    .get_args()
+                    .map(|arg| arg.to_string_lossy())
+                    .collect::<Vec<_>>()
+                    .join(" "),
+                stdout: String::from_utf8_lossy(&output.stdout),
+                stderr: String::from_utf8_lossy(&output.stderr),
+            })
+        }
+        _ => {}
+    }
+}
+
+fn find_binutils_dlltool(sess: &Session) -> OsString {
+    assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
+    if let Some(dlltool_path) = &sess.opts.cg.dlltool {
+        return dlltool_path.clone().into_os_string();
+    }
+
+    let tool_name: OsString = if sess.host.options.is_like_windows {
+        // If we're compiling on Windows, always use "dlltool.exe".
+        "dlltool.exe"
+    } else {
+        // On other platforms, use the architecture-specific name.
+        match sess.target.arch.as_ref() {
+            "x86_64" => "x86_64-w64-mingw32-dlltool",
+            "x86" => "i686-w64-mingw32-dlltool",
+            "aarch64" => "aarch64-w64-mingw32-dlltool",
+
+            // For non-standard architectures (e.g., aarch32) fallback to "dlltool".
+            _ => "dlltool",
+        }
+    }
+    .into();
+
+    // NOTE: it's not clear how useful it is to explicitly search PATH.
+    for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
+        let full_path = dir.join(&tool_name);
+        if full_path.is_file() {
+            return full_path.into_os_string();
+        }
+    }
+
+    // The user didn't specify the location of the dlltool binary, and we weren't able
+    // to find the appropriate one on the PATH. Just return the name of the tool
+    // and let the invocation fail with a hopefully useful error message.
+    tool_name
+}
+
 pub trait ArchiveBuilder {
     fn add_file(&mut self, path: &Path);
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 7d457526380..7bad9d33e7d 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -51,7 +51,8 @@ use super::linker::{self, Linker};
 use super::metadata::{create_wrapper_file, MetadataPosition};
 use super::rpath::{self, RPathConfig};
 use crate::{
-    errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+    common, errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo,
+    NativeLib,
 };
 
 pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
@@ -390,17 +391,13 @@ fn link_rlib<'a>(
         }
     }
 
-    for (raw_dylib_name, raw_dylib_imports) in
-        collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
-    {
-        let output_path = archive_builder_builder.create_dll_import_lib(
-            sess,
-            &raw_dylib_name,
-            &raw_dylib_imports,
-            tmpdir.as_ref(),
-            true,
-        );
-
+    for output_path in create_dll_import_libs(
+        sess,
+        archive_builder_builder,
+        codegen_results.crate_info.used_libraries.iter(),
+        tmpdir.as_ref(),
+        true,
+    )? {
         ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
             sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
         });
@@ -488,6 +485,47 @@ fn collate_raw_dylibs<'a>(
         .collect())
 }
 
+fn create_dll_import_libs<'a>(
+    sess: &Session,
+    archive_builder_builder: &dyn ArchiveBuilderBuilder,
+    used_libraries: impl IntoIterator<Item = &'a NativeLib>,
+    tmpdir: &Path,
+    is_direct_dependency: bool,
+) -> Result<Vec<PathBuf>, ErrorGuaranteed> {
+    Ok(collate_raw_dylibs(sess, used_libraries)?
+        .into_iter()
+        .map(|(raw_dylib_name, raw_dylib_imports)| {
+            let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
+            let output_path = tmpdir.join(format!("{raw_dylib_name}{name_suffix}.lib"));
+
+            let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target);
+
+            let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = raw_dylib_imports
+                .iter()
+                .map(|import: &DllImport| {
+                    if sess.target.arch == "x86" {
+                        (
+                            common::i686_decorated_name(import, mingw_gnu_toolchain, false),
+                            import.ordinal(),
+                        )
+                    } else {
+                        (import.name.to_string(), import.ordinal())
+                    }
+                })
+                .collect();
+
+            archive_builder_builder.create_dll_import_lib(
+                sess,
+                &raw_dylib_name,
+                import_name_and_ordinal_vector,
+                &output_path,
+            );
+
+            output_path
+        })
+        .collect())
+}
+
 /// Create a static archive.
 ///
 /// This is essentially the same thing as an rlib, but it also involves adding all of the upstream
@@ -2065,17 +2103,61 @@ fn add_local_crate_metadata_objects(
 }
 
 /// Add sysroot and other globally set directories to the directory search list.
-fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
-    // The default library location, we need this to find the runtime.
-    // The location of crates will be determined as needed.
-    let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
-    cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+fn add_library_search_dirs(
+    cmd: &mut dyn Linker,
+    sess: &Session,
+    self_contained_components: LinkSelfContainedComponents,
+    apple_sdk_root: Option<&Path>,
+) {
+    if !sess.opts.unstable_opts.link_native_libraries {
+        return;
+    }
 
-    // Special directory with libraries used only in self-contained linkage mode
-    if self_contained {
-        let lib_path = sess.target_filesearch(PathKind::All).get_self_contained_lib_path();
+    // Library search paths explicitly supplied by user (`-L` on the command line).
+    for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
+        cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir));
+    }
+    for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
+        // Contrary to the `-L` docs only framework-specific paths are considered here.
+        if search_path.kind != PathKind::All {
+            cmd.framework_path(&search_path.dir);
+        }
+    }
+
+    // The toolchain ships some native library components and self-contained linking was enabled.
+    // Add the self-contained library directory to search paths.
+    if self_contained_components.intersects(
+        LinkSelfContainedComponents::LIBC
+            | LinkSelfContainedComponents::UNWIND
+            | LinkSelfContainedComponents::MINGW,
+    ) {
+        let lib_path = sess.target_filesearch(PathKind::Native).get_self_contained_lib_path();
         cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
     }
+
+    // Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
+    // library directory instead of the self-contained directories.
+    // Sanitizer libraries have the same issue and are also linked by name on Apple targets.
+    // The targets here should be in sync with `copy_third_party_objects` in bootstrap.
+    // FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
+    // and sanitizers to self-contained directory, and stop adding this search path.
+    if sess.target.vendor == "fortanix"
+        || sess.target.os == "linux"
+        || sess.target.os == "fuchsia"
+        || sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
+    {
+        let lib_path = sess.target_filesearch(PathKind::Native).get_lib_path();
+        cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+    }
+
+    // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
+    // we must have the support library stubs in the library search path (#121430).
+    if let Some(sdk_root) = apple_sdk_root
+        && sess.target.llvm_target.contains("macabi")
+    {
+        cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
+        cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
+    }
 }
 
 /// Add options making relocation sections in the produced ELF files read-only
@@ -2261,16 +2343,14 @@ fn linker_with_args(
     );
 
     // Link with the import library generated for any raw-dylib functions.
-    for (raw_dylib_name, raw_dylib_imports) in
-        collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
-    {
-        cmd.add_object(&archive_builder_builder.create_dll_import_lib(
-            sess,
-            &raw_dylib_name,
-            &raw_dylib_imports,
-            tmpdir,
-            true,
-        ));
+    for output_path in create_dll_import_libs(
+        sess,
+        archive_builder_builder,
+        codegen_results.crate_info.used_libraries.iter(),
+        tmpdir,
+        true,
+    )? {
+        cmd.add_object(&output_path);
     }
     // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
     // they are used within inlined functions or instantiated generic functions. We do this *after*
@@ -2295,16 +2375,14 @@ fn linker_with_args(
         .flatten()
         .collect::<Vec<_>>();
     native_libraries_from_nonstatics.sort_unstable_by(|a, b| a.name.as_str().cmp(b.name.as_str()));
-    for (raw_dylib_name, raw_dylib_imports) in
-        collate_raw_dylibs(sess, native_libraries_from_nonstatics)?
-    {
-        cmd.add_object(&archive_builder_builder.create_dll_import_lib(
-            sess,
-            &raw_dylib_name,
-            &raw_dylib_imports,
-            tmpdir,
-            false,
-        ));
+    for output_path in create_dll_import_libs(
+        sess,
+        archive_builder_builder,
+        native_libraries_from_nonstatics,
+        tmpdir,
+        false,
+    )? {
+        cmd.add_object(&output_path);
     }
 
     // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
@@ -2367,7 +2445,7 @@ fn add_order_independent_options(
     // Take care of the flavors and CLI options requesting the `lld` linker.
     add_lld_args(cmd, sess, flavor, self_contained_components);
 
-    add_apple_sdk(cmd, sess, flavor);
+    let apple_sdk_root = add_apple_sdk(cmd, sess, flavor);
 
     add_link_script(cmd, sess, tmpdir, crate_type);
 
@@ -2423,7 +2501,7 @@ fn add_order_independent_options(
 
     cmd.linker_plugin_lto();
 
-    add_library_search_dirs(cmd, sess, self_contained_components.are_any_components_enabled());
+    add_library_search_dirs(cmd, sess, self_contained_components, apple_sdk_root.as_deref());
 
     cmd.output_filename(out_filename);
 
@@ -2568,16 +2646,7 @@ fn add_native_libs_from_crate(
             NativeLibKind::Static { bundle, whole_archive } => {
                 if link_static {
                     let bundle = bundle.unwrap_or(true);
-                    let whole_archive = whole_archive == Some(true)
-                        // Backward compatibility case: this can be a rlib (so `+whole-archive`
-                        // cannot be added explicitly if necessary, see the error in `fn link_rlib`)
-                        // compiled as an executable due to `--test`. Use whole-archive implicitly,
-                        // like before the introduction of native lib modifiers.
-                        || (whole_archive == None
-                            && bundle
-                            && cnum == LOCAL_CRATE
-                            && sess.is_test_crate());
-
+                    let whole_archive = whole_archive == Some(true);
                     if bundle && cnum != LOCAL_CRATE {
                         if let Some(filename) = lib.filename {
                             // If rlib contains native libs as archives, they are unpacked to tmpdir.
@@ -2637,19 +2706,6 @@ fn add_local_native_libraries(
     tmpdir: &Path,
     link_output_kind: LinkOutputKind,
 ) {
-    if sess.opts.unstable_opts.link_native_libraries {
-        // User-supplied library search paths (-L on the command line). These are the same paths
-        // used to find Rust crates, so some of them may have been added already by the previous
-        // crate linking code. This only allows them to be found at compile time so it is still
-        // entirely up to outside forces to make sure that library can be found at runtime.
-        for search_path in sess.target_filesearch(PathKind::All).search_paths() {
-            match search_path.kind {
-                PathKind::Framework => cmd.framework_path(&search_path.dir),
-                _ => cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir)),
-            }
-        }
-    }
-
     // All static and dynamic native library dependencies are linked to the local crate.
     let link_static = true;
     let link_dynamic = true;
@@ -2944,7 +3000,7 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool
     }
 }
 
-fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
+fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option<PathBuf> {
     let arch = &sess.target.arch;
     let os = &sess.target.os;
     let llvm_target = &sess.target.llvm_target;
@@ -2952,11 +3008,11 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "visionos" | "macos")
         || !matches!(flavor, LinkerFlavor::Darwin(..))
     {
-        return;
+        return None;
     }
 
     if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) {
-        return;
+        return None;
     }
 
     let sdk_name = match (arch.as_ref(), os.as_ref()) {
@@ -2980,14 +3036,14 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         (_, "macos") => "macosx",
         _ => {
             sess.dcx().emit_err(errors::UnsupportedArch { arch, os });
-            return;
+            return None;
         }
     };
     let sdk_root = match get_apple_sdk_root(sdk_name) {
         Ok(s) => s,
         Err(e) => {
             sess.dcx().emit_err(e);
-            return;
+            return None;
         }
     };
 
@@ -3007,16 +3063,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         _ => unreachable!(),
     }
 
-    if llvm_target.contains("macabi") {
-        // Mac Catalyst uses the macOS SDK, but to link to iOS-specific
-        // frameworks, we must have the support library stubs in the library
-        // search path.
-
-        // The flags are called `-L` and `-F` both in Clang, ld64 and ldd.
-        let sdk_root = Path::new(&sdk_root);
-        cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
-        cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
-    }
+    Some(sdk_root.into())
 }
 
 fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootError<'_>> {
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 19394029c94..9b5a797ad51 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -208,6 +208,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
         "powerpc64" => (Architecture::PowerPc64, None),
         "riscv32" => (Architecture::Riscv32, None),
         "riscv64" => (Architecture::Riscv64, None),
+        "sparc" => (Architecture::Sparc32Plus, None),
         "sparc64" => (Architecture::Sparc64, None),
         "avr" => (Architecture::Avr, None),
         "msp430" => (Architecture::Msp430, None),
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f4e44e63d73..f1e7f87f567 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -143,7 +143,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 ) -> Bx::Value {
     let cx = bx.cx();
     let (source, target) =
-        cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env());
+        cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.param_env());
     match (source.kind(), target.kind()) {
         (&ty::Array(_, len), &ty::Slice(_)) => {
             cx.const_usize(len.eval_target_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 741c0f090e9..bfb1d217eae 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -4,11 +4,13 @@ use rustc_hir::LangItem;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_middle::{bug, mir, span_bug};
+use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
 use rustc_span::Span;
+use rustc_target::spec::Target;
 
 use crate::traits::*;
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum IntPredicate {
     IntEQ,
     IntNE,
@@ -22,7 +24,7 @@ pub enum IntPredicate {
     IntSLE,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum RealPredicate {
     RealPredicateFalse,
     RealOEQ,
@@ -42,7 +44,7 @@ pub enum RealPredicate {
     RealPredicateTrue,
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum AtomicRmwBinOp {
     AtomicXchg,
     AtomicAdd,
@@ -57,7 +59,7 @@ pub enum AtomicRmwBinOp {
     AtomicUMin,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum AtomicOrdering {
     Unordered,
     Relaxed,
@@ -67,7 +69,7 @@ pub enum AtomicOrdering {
     SequentiallyConsistent,
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum SynchronizationScope {
     SingleThread,
     CrossThread,
@@ -176,3 +178,66 @@ pub fn asm_const_to_str<'tcx>(
         _ => span_bug!(sp, "asm const has bad type {}", ty_and_layout.ty),
     }
 }
+
+pub fn is_mingw_gnu_toolchain(target: &Target) -> bool {
+    target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
+}
+
+pub fn i686_decorated_name(
+    dll_import: &DllImport,
+    mingw: bool,
+    disable_name_mangling: bool,
+) -> String {
+    let name = dll_import.name.as_str();
+
+    let (add_prefix, add_suffix) = match dll_import.import_name_type {
+        Some(PeImportNameType::NoPrefix) => (false, true),
+        Some(PeImportNameType::Undecorated) => (false, false),
+        _ => (true, true),
+    };
+
+    // Worst case: +1 for disable name mangling, +1 for prefix, +4 for suffix (@@__).
+    let mut decorated_name = String::with_capacity(name.len() + 6);
+
+    if disable_name_mangling {
+        // LLVM uses a binary 1 ('\x01') prefix to a name to indicate that mangling needs to be disabled.
+        decorated_name.push('\x01');
+    }
+
+    let prefix = if add_prefix && dll_import.is_fn {
+        match dll_import.calling_convention {
+            DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
+            DllCallingConvention::Stdcall(_) => (!mingw
+                || dll_import.import_name_type == Some(PeImportNameType::Decorated))
+            .then_some('_'),
+            DllCallingConvention::Fastcall(_) => Some('@'),
+        }
+    } else if !dll_import.is_fn && !mingw {
+        // For static variables, prefix with '_' on MSVC.
+        Some('_')
+    } else {
+        None
+    };
+    if let Some(prefix) = prefix {
+        decorated_name.push(prefix);
+    }
+
+    decorated_name.push_str(name);
+
+    if add_suffix && dll_import.is_fn {
+        use std::fmt::Write;
+
+        match dll_import.calling_convention {
+            DllCallingConvention::C => {}
+            DllCallingConvention::Stdcall(arg_list_size)
+            | DllCallingConvention::Fastcall(arg_list_size) => {
+                write!(&mut decorated_name, "@{arg_list_size}").unwrap();
+            }
+            DllCallingConvention::Vectorcall(arg_list_size) => {
+                write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
+            }
+        }
+    }
+
+    decorated_name
+}
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 2d1eae630cf..94bf0ab34e2 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1027,6 +1027,28 @@ pub struct FailedToGetLayout<'tcx> {
 }
 
 #[derive(Diagnostic)]
+#[diag(codegen_ssa_dlltool_fail_import_library)]
+pub(crate) struct DlltoolFailImportLibrary<'a> {
+    pub dlltool_path: Cow<'a, str>,
+    pub dlltool_args: String,
+    pub stdout: Cow<'a, str>,
+    pub stderr: Cow<'a, str>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_error_writing_def_file)]
+pub(crate) struct ErrorWritingDEFFile {
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_error_calling_dlltool)]
+pub(crate) struct ErrorCallingDllTool<'a> {
+    pub dlltool_path: Cow<'a, str>,
+    pub error: std::io::Error,
+}
+
+#[derive(Diagnostic)]
 #[diag(codegen_ssa_error_creating_remark_dir)]
 pub struct ErrorCreatingRemarkDir {
     pub error: std::io::Error,
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 77da4e4caea..cf8f7fa25d8 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,11 +1,12 @@
 use rustc_ast::ast;
 use rustc_attr::InstructionSetAttr;
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::unord::UnordMap;
+use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::Applicability;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_middle::bug;
+use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
@@ -18,7 +19,7 @@ pub fn from_target_feature(
     tcx: TyCtxt<'_>,
     attr: &ast::Attribute,
     supported_target_features: &UnordMap<String, Option<Symbol>>,
-    target_features: &mut Vec<Symbol>,
+    target_features: &mut Vec<TargetFeature>,
 ) {
     let Some(list) = attr.meta_item_list() else { return };
     let bad_item = |span| {
@@ -30,6 +31,7 @@ pub fn from_target_feature(
             .emit();
     };
     let rust_features = tcx.features();
+    let mut added_target_features = Vec::new();
     for item in list {
         // Only `enable = ...` is accepted in the meta-item list.
         if !item.has_name(sym::enable) {
@@ -44,7 +46,7 @@ pub fn from_target_feature(
         };
 
         // We allow comma separation to enable multiple features.
-        target_features.extend(value.as_str().split(',').filter_map(|feature| {
+        added_target_features.extend(value.as_str().split(',').filter_map(|feature| {
             let Some(feature_gate) = supported_target_features.get(feature) else {
                 let msg = format!("the feature named `{feature}` is not valid for this target");
                 let mut err = tcx.dcx().struct_span_err(item.span(), msg);
@@ -78,6 +80,7 @@ pub fn from_target_feature(
                 Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
                 Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature,
                 Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
+                Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86,
                 Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics,
                 Some(sym::xop_target_feature) => rust_features.xop_target_feature,
                 Some(sym::s390x_target_feature) => rust_features.s390x_target_feature,
@@ -96,6 +99,27 @@ pub fn from_target_feature(
             Some(Symbol::intern(feature))
         }));
     }
+
+    // Add explicit features
+    target_features.extend(
+        added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
+    );
+
+    // Add implied features
+    let mut implied_target_features = UnordSet::new();
+    for feature in added_target_features.iter() {
+        implied_target_features.extend(tcx.implied_target_features(*feature).clone());
+    }
+    for feature in added_target_features.iter() {
+        implied_target_features.remove(feature);
+    }
+    target_features.extend(
+        implied_target_features
+            .into_sorted_stable_ord()
+            .iter()
+            .copied()
+            .map(|name| TargetFeature { name, implied: true }),
+    )
 }
 
 /// Computes the set of target features used in a function for the purposes of
@@ -104,7 +128,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
     let mut target_features = tcx.sess.unstable_target_features.clone();
     if tcx.def_kind(did).has_codegen_attrs() {
         let attrs = tcx.codegen_fn_attrs(did);
-        target_features.extend(&attrs.target_features);
+        target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
         match attrs.instruction_set {
             None => {}
             Some(InstructionSetAttr::ArmA32) => {
@@ -149,10 +173,14 @@ pub(crate) fn provide(providers: &mut Providers) {
                     .target
                     .supported_target_features()
                     .iter()
-                    .map(|&(a, b)| (a.to_string(), b.as_feature_name()))
+                    .map(|&(a, b, _)| (a.to_string(), b.as_feature_name()))
                     .collect()
             }
         },
+        implied_target_features: |tcx, feature| {
+            UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
+                .into_sorted_stable_ord()
+        },
         asm_target_features,
         ..*providers
     }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 0495902dda5..2b802240e03 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -23,7 +23,7 @@ use crate::mir::operand::{OperandRef, OperandValue};
 use crate::mir::place::{PlaceRef, PlaceValue};
 use crate::MemFlags;
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum OverflowOp {
     Add,
     Sub,
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 80dad79179a..7c042c0c621 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -91,7 +91,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
             return false;
         }
 
-        let tail = self.tcx().struct_tail_erasing_lifetimes(ty, param_env);
+        let tail = self.tcx().struct_tail_for_codegen(ty, param_env);
         match tail.kind() {
             ty::Foreign(..) => false,
             ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index ba4b80d1026..ff27e400016 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -73,7 +73,9 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
         cid.promoted.map_or_else(String::new, |p| format!("::{p:?}"))
     );
 
-    ecx.push_stack_frame(
+    // This can't use `init_stack_frame` since `body` is not a function,
+    // so computing its ABI would fail. It's also not worth it since there are no arguments to pass.
+    ecx.push_stack_frame_raw(
         cid.instance,
         body,
         &ret.clone().into(),
@@ -396,7 +398,7 @@ fn const_validate_mplace<'tcx>(
     let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
     let mut ref_tracking = RefTracking::new(mplace.clone());
     let mut inner = false;
-    while let Some((mplace, path)) = ref_tracking.todo.pop() {
+    while let Some((mplace, path)) = ref_tracking.next() {
         let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
             _ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
             Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 901149825bf..a075bdc1911 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -24,8 +24,9 @@ use crate::errors::{LongRunning, LongRunningWarn};
 use crate::fluent_generated as fluent;
 use crate::interpret::{
     self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, throw_unsup,
-    throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal, Frame,
+    throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
     GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
+    StackPopCleanup,
 };
 
 /// When hitting this many interpreted terminators we emit a deny by default lint
@@ -306,17 +307,15 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
                     let align = ImmTy::from_uint(target_align, args[1].layout).into();
                     let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
 
-                    // We replace the entire function call with a "tail call".
-                    // Note that this happens before the frame of the original function
-                    // is pushed on the stack.
-                    self.eval_fn_call(
-                        FnVal::Instance(instance),
-                        (CallAbi::Rust, fn_abi),
+                    // Push the stack frame with our own adjusted arguments.
+                    self.init_stack_frame(
+                        instance,
+                        self.load_mir(instance.def, None)?,
+                        fn_abi,
                         &[FnArg::Copy(addr), FnArg::Copy(align)],
                         /* with_caller_location = */ false,
                         dest,
-                        ret,
-                        mir::UnwindAction::Unreachable,
+                        StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Unreachable },
                     )?;
                     Ok(ControlFlow::Break(()))
                 } else {
@@ -458,7 +457,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         _unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
         // Shared intrinsics.
-        if ecx.emulate_intrinsic(instance, args, dest, target)? {
+        if ecx.eval_intrinsic(instance, args, dest, target)? {
             return Ok(None);
         }
         let intrinsic_name = ecx.tcx.item_name(instance.def_id());
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 47d0e22b527..fdbdfc7e1b8 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -1,24 +1,23 @@
+//! Manages calling a concrete function (with known MIR body) with argument passing,
+//! and returning the return value to the caller.
 use std::borrow::Cow;
 
-use either::Either;
+use either::{Left, Right};
 use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, AdtDef, Instance, Ty};
 use rustc_middle::{bug, mir, span_bug};
-use rustc_span::source_map::Spanned;
 use rustc_span::sym;
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
 use rustc_target::abi::{self, FieldIdx, Integer};
 use rustc_target::spec::abi::Abi;
-use tracing::trace;
+use tracing::{info, instrument, trace};
 
 use super::{
     throw_ub, throw_ub_custom, throw_unsup_format, CtfeProvenance, FnVal, ImmTy, InterpCx,
-    InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, Scalar,
-    StackPopCleanup,
+    InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, ReturnAction, Scalar,
+    StackPopCleanup, StackPopInfo,
 };
 use crate::fluent_generated as fluent;
-use crate::interpret::eval_context::StackPopInfo;
-use crate::interpret::ReturnAction;
 
 /// An argment passed to a function.
 #[derive(Clone, Debug)]
@@ -39,15 +38,6 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
     }
 }
 
-struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> {
-    callee: FnVal<'tcx, M::ExtraFnVal>,
-    args: Vec<FnArg<'tcx, M::Provenance>>,
-    fn_sig: ty::FnSig<'tcx>,
-    fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
-    /// True if the function is marked as `#[track_caller]` ([`ty::InstanceKind::requires_caller_location`])
-    with_caller_location: bool,
-}
-
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
     /// original memory occurs.
@@ -67,7 +57,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
     }
 
-    pub fn fn_arg_field(
+    /// Helper function for argument untupling.
+    pub(super) fn fn_arg_field(
         &self,
         arg: &FnArg<'tcx, M::Provenance>,
         field: usize,
@@ -78,190 +69,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         })
     }
 
-    pub(super) fn eval_terminator(
-        &mut self,
-        terminator: &mir::Terminator<'tcx>,
-    ) -> InterpResult<'tcx> {
-        use rustc_middle::mir::TerminatorKind::*;
-        match terminator.kind {
-            Return => {
-                self.return_from_current_stack_frame(/* unwinding */ false)?
-            }
-
-            Goto { target } => self.go_to_block(target),
-
-            SwitchInt { ref discr, ref targets } => {
-                let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;
-                trace!("SwitchInt({:?})", *discr);
-
-                // Branch to the `otherwise` case by default, if no match is found.
-                let mut target_block = targets.otherwise();
-
-                for (const_int, target) in targets.iter() {
-                    // Compare using MIR BinOp::Eq, to also support pointer values.
-                    // (Avoiding `self.binary_op` as that does some redundant layout computation.)
-                    let res = self.binary_op(
-                        mir::BinOp::Eq,
-                        &discr,
-                        &ImmTy::from_uint(const_int, discr.layout),
-                    )?;
-                    if res.to_scalar().to_bool()? {
-                        target_block = target;
-                        break;
-                    }
-                }
-
-                self.go_to_block(target_block);
-            }
-
-            Call {
-                ref func,
-                ref args,
-                destination,
-                target,
-                unwind,
-                call_source: _,
-                fn_span: _,
-            } => {
-                let old_stack = self.frame_idx();
-                let old_loc = self.frame().loc;
-
-                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
-                    self.eval_callee_and_args(terminator, func, args)?;
-
-                let destination = self.force_allocation(&self.eval_place(destination)?)?;
-                self.eval_fn_call(
-                    callee,
-                    (fn_sig.abi, fn_abi),
-                    &args,
-                    with_caller_location,
-                    &destination,
-                    target,
-                    if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
-                )?;
-                // Sanity-check that `eval_fn_call` either pushed a new frame or
-                // did a jump to another block.
-                if self.frame_idx() == old_stack && self.frame().loc == old_loc {
-                    span_bug!(terminator.source_info.span, "evaluating this call made no progress");
-                }
-            }
-
-            TailCall { ref func, ref args, fn_span: _ } => {
-                let old_frame_idx = self.frame_idx();
-
-                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
-                    self.eval_callee_and_args(terminator, func, args)?;
-
-                self.eval_fn_tail_call(callee, (fn_sig.abi, fn_abi), &args, with_caller_location)?;
-
-                if self.frame_idx() != old_frame_idx {
-                    span_bug!(
-                        terminator.source_info.span,
-                        "evaluating this tail call pushed a new stack frame"
-                    );
-                }
-            }
-
-            Drop { place, target, unwind, replace: _ } => {
-                let place = self.eval_place(place)?;
-                let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
-                if let ty::InstanceKind::DropGlue(_, None) = instance.def {
-                    // This is the branch we enter if and only if the dropped type has no drop glue
-                    // whatsoever. This can happen as a result of monomorphizing a drop of a
-                    // generic. In order to make sure that generic and non-generic code behaves
-                    // roughly the same (and in keeping with Mir semantics) we do nothing here.
-                    self.go_to_block(target);
-                    return Ok(());
-                }
-                trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty);
-                self.drop_in_place(&place, instance, target, unwind)?;
-            }
-
-            Assert { ref cond, expected, ref msg, target, unwind } => {
-                let ignored =
-                    M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
-                let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
-                if ignored || expected == cond_val {
-                    self.go_to_block(target);
-                } else {
-                    M::assert_panic(self, msg, unwind)?;
-                }
-            }
-
-            UnwindTerminate(reason) => {
-                M::unwind_terminate(self, reason)?;
-            }
-
-            // When we encounter Resume, we've finished unwinding
-            // cleanup for the current stack frame. We pop it in order
-            // to continue unwinding the next frame
-            UnwindResume => {
-                trace!("unwinding: resuming from cleanup");
-                // By definition, a Resume terminator means
-                // that we're unwinding
-                self.return_from_current_stack_frame(/* unwinding */ true)?;
-                return Ok(());
-            }
-
-            // It is UB to ever encounter this.
-            Unreachable => throw_ub!(Unreachable),
-
-            // These should never occur for MIR we actually run.
-            FalseEdge { .. } | FalseUnwind { .. } | Yield { .. } | CoroutineDrop => span_bug!(
-                terminator.source_info.span,
-                "{:#?} should have been eliminated by MIR pass",
-                terminator.kind
-            ),
-
-            InlineAsm { template, ref operands, options, ref targets, .. } => {
-                M::eval_inline_asm(self, template, operands, options, targets)?;
-            }
-        }
-
-        Ok(())
-    }
-
-    /// Evaluate the arguments of a function call
-    pub(super) fn eval_fn_call_arguments(
-        &self,
-        ops: &[Spanned<mir::Operand<'tcx>>],
-    ) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>> {
-        ops.iter()
-            .map(|op| {
-                let arg = match &op.node {
-                    mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
-                        // Make a regular copy.
-                        let op = self.eval_operand(&op.node, None)?;
-                        FnArg::Copy(op)
-                    }
-                    mir::Operand::Move(place) => {
-                        // If this place lives in memory, preserve its location.
-                        // We call `place_to_op` which will be an `MPlaceTy` whenever there exists
-                        // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
-                        // which can return a local even if that has an mplace.)
-                        let place = self.eval_place(*place)?;
-                        let op = self.place_to_op(&place)?;
-
-                        match op.as_mplace_or_imm() {
-                            Either::Left(mplace) => FnArg::InPlace(mplace),
-                            Either::Right(_imm) => {
-                                // This argument doesn't live in memory, so there's no place
-                                // to make inaccessible during the call.
-                                // We rely on there not being any stray `PlaceTy` that would let the
-                                // caller directly access this local!
-                                // This is also crucial for tail calls, where we want the `FnArg` to
-                                // stay valid when the old stack frame gets popped.
-                                FnArg::Copy(op)
-                            }
-                        }
-                    }
-                };
-
-                Ok(arg)
-            })
-            .collect()
-    }
-
     /// Find the wrapped inner type of a transparent wrapper.
     /// Must not be called on 1-ZST (as they don't have a uniquely defined "wrapped field").
     ///
@@ -503,46 +310,206 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(())
     }
 
-    /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the
-    /// necessary information about callee and arguments to make a call.
-    fn eval_callee_and_args(
-        &self,
-        terminator: &mir::Terminator<'tcx>,
-        func: &mir::Operand<'tcx>,
-        args: &[Spanned<mir::Operand<'tcx>>],
-    ) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
-        let func = self.eval_operand(func, None)?;
-        let args = self.eval_fn_call_arguments(args)?;
-
-        let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
-        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
-        let extra_args = &args[fn_sig.inputs().len()..];
-        let extra_args =
-            self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
-
-        let (callee, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
-            ty::FnPtr(_sig) => {
-                let fn_ptr = self.read_pointer(&func)?;
-                let fn_val = self.get_ptr_fn(fn_ptr)?;
-                (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false)
-            }
-            ty::FnDef(def_id, args) => {
-                let instance = self.resolve(def_id, args)?;
-                (
-                    FnVal::Instance(instance),
-                    self.fn_abi_of_instance(instance, extra_args)?,
-                    instance.def.requires_caller_location(*self.tcx),
+    fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
+        // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
+        let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+        if !self.tcx.sess.target.is_like_wasm
+            && attrs
+                .target_features
+                .iter()
+                .any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
+        {
+            throw_ub_custom!(
+                fluent::const_eval_unavailable_target_features_for_fn,
+                unavailable_feats = attrs
+                    .target_features
+                    .iter()
+                    .filter(|&feature| !feature.implied
+                        && !self.tcx.sess.target_features.contains(&feature.name))
+                    .fold(String::new(), |mut s, feature| {
+                        if !s.is_empty() {
+                            s.push_str(", ");
+                        }
+                        s.push_str(feature.name.as_str());
+                        s
+                    }),
+            );
+        }
+        Ok(())
+    }
+
+    /// The main entry point for creating a new stack frame: performs ABI checks and initializes
+    /// arguments.
+    #[instrument(skip(self), level = "trace")]
+    pub fn init_stack_frame(
+        &mut self,
+        instance: Instance<'tcx>,
+        body: &'tcx mir::Body<'tcx>,
+        caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+        args: &[FnArg<'tcx, M::Provenance>],
+        with_caller_location: bool,
+        destination: &MPlaceTy<'tcx, M::Provenance>,
+        mut stack_pop: StackPopCleanup,
+    ) -> InterpResult<'tcx> {
+        // Compute callee information.
+        // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
+        let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
+
+        if callee_fn_abi.c_variadic || caller_fn_abi.c_variadic {
+            throw_unsup_format!("calling a c-variadic function is not supported");
+        }
+
+        if M::enforce_abi(self) {
+            if caller_fn_abi.conv != callee_fn_abi.conv {
+                throw_ub_custom!(
+                    fluent::const_eval_incompatible_calling_conventions,
+                    callee_conv = format!("{:?}", callee_fn_abi.conv),
+                    caller_conv = format!("{:?}", caller_fn_abi.conv),
                 )
             }
-            _ => {
-                span_bug!(terminator.source_info.span, "invalid callee of type {}", func.layout.ty)
+        }
+
+        // Check that all target features required by the callee (i.e., from
+        // the attribute `#[target_feature(enable = ...)]`) are enabled at
+        // compile time.
+        self.check_fn_target_features(instance)?;
+
+        if !callee_fn_abi.can_unwind {
+            // The callee cannot unwind, so force the `Unreachable` unwind handling.
+            match &mut stack_pop {
+                StackPopCleanup::Root { .. } => {}
+                StackPopCleanup::Goto { unwind, .. } => {
+                    *unwind = mir::UnwindAction::Unreachable;
+                }
             }
-        };
+        }
+
+        self.push_stack_frame_raw(instance, body, destination, stack_pop)?;
+
+        // If an error is raised here, pop the frame again to get an accurate backtrace.
+        // To this end, we wrap it all in a `try` block.
+        let res: InterpResult<'tcx> = try {
+            trace!(
+                "caller ABI: {:#?}, args: {:#?}",
+                caller_fn_abi,
+                args.iter()
+                    .map(|arg| (
+                        arg.layout().ty,
+                        match arg {
+                            FnArg::Copy(op) => format!("copy({op:?})"),
+                            FnArg::InPlace(mplace) => format!("in-place({mplace:?})"),
+                        }
+                    ))
+                    .collect::<Vec<_>>()
+            );
+            trace!(
+                "spread_arg: {:?}, locals: {:#?}",
+                body.spread_arg,
+                body.args_iter()
+                    .map(|local| (
+                        local,
+                        self.layout_of_local(self.frame(), local, None).unwrap().ty,
+                    ))
+                    .collect::<Vec<_>>()
+            );
+
+            // In principle, we have two iterators: Where the arguments come from, and where
+            // they go to.
+
+            // The "where they come from" part is easy, we expect the caller to do any special handling
+            // that might be required here (e.g. for untupling).
+            // If `with_caller_location` is set we pretend there is an extra argument (that
+            // we will not pass; our `caller_location` intrinsic implementation walks the stack instead).
+            assert_eq!(
+                args.len() + if with_caller_location { 1 } else { 0 },
+                caller_fn_abi.args.len(),
+                "mismatch between caller ABI and caller arguments",
+            );
+            let mut caller_args = args
+                .iter()
+                .zip(caller_fn_abi.args.iter())
+                .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
+
+            // Now we have to spread them out across the callee's locals,
+            // taking into account the `spread_arg`. If we could write
+            // this is a single iterator (that handles `spread_arg`), then
+            // `pass_argument` would be the loop body. It takes care to
+            // not advance `caller_iter` for ignored arguments.
+            let mut callee_args_abis = callee_fn_abi.args.iter();
+            for local in body.args_iter() {
+                // Construct the destination place for this argument. At this point all
+                // locals are still dead, so we cannot construct a `PlaceTy`.
+                let dest = mir::Place::from(local);
+                // `layout_of_local` does more than just the instantiation we need to get the
+                // type, but the result gets cached so this avoids calling the instantiation
+                // query *again* the next time this local is accessed.
+                let ty = self.layout_of_local(self.frame(), local, None)?.ty;
+                if Some(local) == body.spread_arg {
+                    // Make the local live once, then fill in the value field by field.
+                    self.storage_live(local)?;
+                    // Must be a tuple
+                    let ty::Tuple(fields) = ty.kind() else {
+                        span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}")
+                    };
+                    for (i, field_ty) in fields.iter().enumerate() {
+                        let dest = dest.project_deeper(
+                            &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
+                            *self.tcx,
+                        );
+                        let callee_abi = callee_args_abis.next().unwrap();
+                        self.pass_argument(
+                            &mut caller_args,
+                            callee_abi,
+                            &dest,
+                            field_ty,
+                            /* already_live */ true,
+                        )?;
+                    }
+                } else {
+                    // Normal argument. Cannot mark it as live yet, it might be unsized!
+                    let callee_abi = callee_args_abis.next().unwrap();
+                    self.pass_argument(
+                        &mut caller_args,
+                        callee_abi,
+                        &dest,
+                        ty,
+                        /* already_live */ false,
+                    )?;
+                }
+            }
+            // If the callee needs a caller location, pretend we consume one more argument from the ABI.
+            if instance.def.requires_caller_location(*self.tcx) {
+                callee_args_abis.next().unwrap();
+            }
+            // Now we should have no more caller args or callee arg ABIs
+            assert!(
+                callee_args_abis.next().is_none(),
+                "mismatch between callee ABI and callee body arguments"
+            );
+            if caller_args.next().is_some() {
+                throw_ub_custom!(fluent::const_eval_too_many_caller_args);
+            }
+            // Don't forget to check the return type!
+            if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
+                throw_ub!(AbiMismatchReturn {
+                    caller_ty: caller_fn_abi.ret.layout.ty,
+                    callee_ty: callee_fn_abi.ret.layout.ty
+                });
+            }
+
+            // Protect return place for in-place return value passing.
+            M::protect_in_place_function_argument(self, &destination)?;
 
-        Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location })
+            // Don't forget to mark "initially live" locals as live.
+            self.storage_live_for_always_live_locals()?;
+        };
+        res.inspect_err(|_| {
+            // Don't show the incomplete stack frame in the error stacktrace.
+            self.stack_mut().pop();
+        })
     }
 
-    /// Call this function -- pushing the stack frame and initializing the arguments.
+    /// Initiate a call to this function -- pushing the stack frame and initializing the arguments.
     ///
     /// `caller_fn_abi` is used to determine if all the arguments are passed the proper way.
     /// However, we also need `caller_abi` to determine if we need to do untupling of arguments.
@@ -550,7 +517,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// `with_caller_location` indicates whether the caller passed a caller location. Miri
     /// implements caller locations without argument passing, but to match `FnAbi` we need to know
     /// when those arguments are present.
-    pub(crate) fn eval_fn_call(
+    pub(super) fn init_fn_call(
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
         (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
@@ -558,9 +525,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         with_caller_location: bool,
         destination: &MPlaceTy<'tcx, M::Provenance>,
         target: Option<mir::BasicBlock>,
-        mut unwind: mir::UnwindAction,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
-        trace!("eval_fn_call: {:#?}", fn_val);
+        trace!("init_fn_call: {:#?}", fn_val);
 
         let instance = match fn_val {
             FnVal::Instance(instance) => instance,
@@ -591,7 +558,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 )? {
                     assert!(!self.tcx.intrinsic(fallback.def_id()).unwrap().must_be_overridden);
                     assert!(matches!(fallback.def, ty::InstanceKind::Item(_)));
-                    return self.eval_fn_call(
+                    return self.init_fn_call(
                         FnVal::Instance(fallback),
                         (caller_abi, caller_fn_abi),
                         args,
@@ -630,189 +597,35 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     return Ok(());
                 };
 
-                // Compute callee information using the `instance` returned by
-                // `find_mir_or_eval_fn`.
-                // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
-                let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
-
-                if callee_fn_abi.c_variadic || caller_fn_abi.c_variadic {
-                    throw_unsup_format!("calling a c-variadic function is not supported");
-                }
-
-                if M::enforce_abi(self) {
-                    if caller_fn_abi.conv != callee_fn_abi.conv {
-                        throw_ub_custom!(
-                            fluent::const_eval_incompatible_calling_conventions,
-                            callee_conv = format!("{:?}", callee_fn_abi.conv),
-                            caller_conv = format!("{:?}", caller_fn_abi.conv),
+                // Special handling for the closure ABI: untuple the last argument.
+                let args: Cow<'_, [FnArg<'tcx, M::Provenance>]> =
+                    if caller_abi == Abi::RustCall && !args.is_empty() {
+                        // Untuple
+                        let (untuple_arg, args) = args.split_last().unwrap();
+                        trace!("init_fn_call: Will pass last argument by untupling");
+                        Cow::from(
+                            args.iter()
+                                .map(|a| Ok(a.clone()))
+                                .chain(
+                                    (0..untuple_arg.layout().fields.count())
+                                        .map(|i| self.fn_arg_field(untuple_arg, i)),
+                                )
+                                .collect::<InterpResult<'_, Vec<_>>>()?,
                         )
-                    }
-                }
-
-                // Check that all target features required by the callee (i.e., from
-                // the attribute `#[target_feature(enable = ...)]`) are enabled at
-                // compile time.
-                self.check_fn_target_features(instance)?;
-
-                if !callee_fn_abi.can_unwind {
-                    // The callee cannot unwind, so force the `Unreachable` unwind handling.
-                    unwind = mir::UnwindAction::Unreachable;
-                }
+                    } else {
+                        // Plain arg passing
+                        Cow::from(args)
+                    };
 
-                self.push_stack_frame(
+                self.init_stack_frame(
                     instance,
                     body,
+                    caller_fn_abi,
+                    &args,
+                    with_caller_location,
                     destination,
                     StackPopCleanup::Goto { ret: target, unwind },
-                )?;
-
-                // If an error is raised here, pop the frame again to get an accurate backtrace.
-                // To this end, we wrap it all in a `try` block.
-                let res: InterpResult<'tcx> = try {
-                    trace!(
-                        "caller ABI: {:?}, args: {:#?}",
-                        caller_abi,
-                        args.iter()
-                            .map(|arg| (
-                                arg.layout().ty,
-                                match arg {
-                                    FnArg::Copy(op) => format!("copy({op:?})"),
-                                    FnArg::InPlace(mplace) => format!("in-place({mplace:?})"),
-                                }
-                            ))
-                            .collect::<Vec<_>>()
-                    );
-                    trace!(
-                        "spread_arg: {:?}, locals: {:#?}",
-                        body.spread_arg,
-                        body.args_iter()
-                            .map(|local| (
-                                local,
-                                self.layout_of_local(self.frame(), local, None).unwrap().ty,
-                            ))
-                            .collect::<Vec<_>>()
-                    );
-
-                    // In principle, we have two iterators: Where the arguments come from, and where
-                    // they go to.
-
-                    // For where they come from: If the ABI is RustCall, we untuple the
-                    // last incoming argument. These two iterators do not have the same type,
-                    // so to keep the code paths uniform we accept an allocation
-                    // (for RustCall ABI only).
-                    let caller_args: Cow<'_, [FnArg<'tcx, M::Provenance>]> =
-                        if caller_abi == Abi::RustCall && !args.is_empty() {
-                            // Untuple
-                            let (untuple_arg, args) = args.split_last().unwrap();
-                            trace!("eval_fn_call: Will pass last argument by untupling");
-                            Cow::from(
-                                args.iter()
-                                    .map(|a| Ok(a.clone()))
-                                    .chain(
-                                        (0..untuple_arg.layout().fields.count())
-                                            .map(|i| self.fn_arg_field(untuple_arg, i)),
-                                    )
-                                    .collect::<InterpResult<'_, Vec<_>>>()?,
-                            )
-                        } else {
-                            // Plain arg passing
-                            Cow::from(args)
-                        };
-                    // If `with_caller_location` is set we pretend there is an extra argument (that
-                    // we will not pass).
-                    assert_eq!(
-                        caller_args.len() + if with_caller_location { 1 } else { 0 },
-                        caller_fn_abi.args.len(),
-                        "mismatch between caller ABI and caller arguments",
-                    );
-                    let mut caller_args = caller_args
-                        .iter()
-                        .zip(caller_fn_abi.args.iter())
-                        .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
-
-                    // Now we have to spread them out across the callee's locals,
-                    // taking into account the `spread_arg`. If we could write
-                    // this is a single iterator (that handles `spread_arg`), then
-                    // `pass_argument` would be the loop body. It takes care to
-                    // not advance `caller_iter` for ignored arguments.
-                    let mut callee_args_abis = callee_fn_abi.args.iter();
-                    for local in body.args_iter() {
-                        // Construct the destination place for this argument. At this point all
-                        // locals are still dead, so we cannot construct a `PlaceTy`.
-                        let dest = mir::Place::from(local);
-                        // `layout_of_local` does more than just the instantiation we need to get the
-                        // type, but the result gets cached so this avoids calling the instantiation
-                        // query *again* the next time this local is accessed.
-                        let ty = self.layout_of_local(self.frame(), local, None)?.ty;
-                        if Some(local) == body.spread_arg {
-                            // Make the local live once, then fill in the value field by field.
-                            self.storage_live(local)?;
-                            // Must be a tuple
-                            let ty::Tuple(fields) = ty.kind() else {
-                                span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}")
-                            };
-                            for (i, field_ty) in fields.iter().enumerate() {
-                                let dest = dest.project_deeper(
-                                    &[mir::ProjectionElem::Field(
-                                        FieldIdx::from_usize(i),
-                                        field_ty,
-                                    )],
-                                    *self.tcx,
-                                );
-                                let callee_abi = callee_args_abis.next().unwrap();
-                                self.pass_argument(
-                                    &mut caller_args,
-                                    callee_abi,
-                                    &dest,
-                                    field_ty,
-                                    /* already_live */ true,
-                                )?;
-                            }
-                        } else {
-                            // Normal argument. Cannot mark it as live yet, it might be unsized!
-                            let callee_abi = callee_args_abis.next().unwrap();
-                            self.pass_argument(
-                                &mut caller_args,
-                                callee_abi,
-                                &dest,
-                                ty,
-                                /* already_live */ false,
-                            )?;
-                        }
-                    }
-                    // If the callee needs a caller location, pretend we consume one more argument from the ABI.
-                    if instance.def.requires_caller_location(*self.tcx) {
-                        callee_args_abis.next().unwrap();
-                    }
-                    // Now we should have no more caller args or callee arg ABIs
-                    assert!(
-                        callee_args_abis.next().is_none(),
-                        "mismatch between callee ABI and callee body arguments"
-                    );
-                    if caller_args.next().is_some() {
-                        throw_ub_custom!(fluent::const_eval_too_many_caller_args);
-                    }
-                    // Don't forget to check the return type!
-                    if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
-                        throw_ub!(AbiMismatchReturn {
-                            caller_ty: caller_fn_abi.ret.layout.ty,
-                            callee_ty: callee_fn_abi.ret.layout.ty
-                        });
-                    }
-
-                    // Protect return place for in-place return value passing.
-                    M::protect_in_place_function_argument(self, &destination)?;
-
-                    // Don't forget to mark "initially live" locals as live.
-                    self.storage_live_for_always_live_locals()?;
-                };
-                match res {
-                    Err(err) => {
-                        self.stack_mut().pop();
-                        Err(err)
-                    }
-                    Ok(()) => Ok(()),
-                }
+                )
             }
             // `InstanceKind::Virtual` does not have callable MIR. Calls to `Virtual` instances must be
             // codegen'd / interpreted as virtual calls through the vtable.
@@ -865,9 +678,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 } else {
                     // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
                     // (For that reason we also cannot use `unpack_dyn_trait`.)
-                    let receiver_tail = self
-                        .tcx
-                        .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
+                    let receiver_tail =
+                        self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.param_env);
                     let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
                         span_bug!(
                             self.cur_span(),
@@ -935,7 +747,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 caller_fn_abi.args[0].layout.ty = receiver_ty;
 
                 // recurse with concrete function
-                self.eval_fn_call(
+                self.init_fn_call(
                     FnVal::Instance(fn_inst),
                     (caller_abi, &caller_fn_abi),
                     &args,
@@ -948,30 +760,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
     }
 
-    pub(crate) fn eval_fn_tail_call(
+    /// Initiate a tail call to this function -- popping the current stack frame, pushing the new
+    /// stack frame and initializing the arguments.
+    pub(super) fn init_fn_tail_call(
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
         (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
         args: &[FnArg<'tcx, M::Provenance>],
         with_caller_location: bool,
     ) -> InterpResult<'tcx> {
-        trace!("eval_fn_call: {:#?}", fn_val);
+        trace!("init_fn_tail_call: {:#?}", fn_val);
 
         // This is the "canonical" implementation of tails calls,
         // a pop of the current stack frame, followed by a normal call
         // which pushes a new stack frame, with the return address from
         // the popped stack frame.
         //
-        // Note that we are using `pop_stack_frame` and not `return_from_current_stack_frame`,
+        // Note that we are using `pop_stack_frame_raw` and not `return_from_current_stack_frame`,
         // as the latter "executes" the goto to the return block, but we don't want to,
         // only the tail called function should return to the current return block.
         M::before_stack_pop(self, self.frame())?;
 
         let StackPopInfo { return_action, return_to_block, return_place } =
-            self.pop_stack_frame(false)?;
+            self.pop_stack_frame_raw(false)?;
 
         assert_eq!(return_action, ReturnAction::Normal);
 
+        // Take the "stack pop cleanup" info, and use that to initiate the next call.
         let StackPopCleanup::Goto { ret, unwind } = return_to_block else {
             bug!("can't tailcall as root");
         };
@@ -980,7 +795,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         //   we should check if both caller&callee can/n't unwind,
         //   see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803>
 
-        self.eval_fn_call(
+        self.init_fn_call(
             fn_val,
             (caller_abi, caller_fn_abi),
             args,
@@ -991,41 +806,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         )
     }
 
-    fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
-        // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
-        let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
-        if !self.tcx.sess.target.is_like_wasm
-            && attrs
-                .target_features
-                .iter()
-                .any(|feature| !self.tcx.sess.target_features.contains(feature))
-        {
-            throw_ub_custom!(
-                fluent::const_eval_unavailable_target_features_for_fn,
-                unavailable_feats = attrs
-                    .target_features
-                    .iter()
-                    .filter(|&feature| !self.tcx.sess.target_features.contains(feature))
-                    .fold(String::new(), |mut s, feature| {
-                        if !s.is_empty() {
-                            s.push_str(", ");
-                        }
-                        s.push_str(feature.as_str());
-                        s
-                    }),
-            );
-        }
-        Ok(())
-    }
-
-    fn drop_in_place(
+    pub(super) fn init_drop_in_place_call(
         &mut self,
         place: &PlaceTy<'tcx, M::Provenance>,
         instance: ty::Instance<'tcx>,
         target: mir::BasicBlock,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
-        trace!("drop_in_place: {:?},\n  instance={:?}", place, instance);
+        trace!("init_drop_in_place_call: {:?},\n  instance={:?}", place, instance);
         // We take the address of the object. This may well be unaligned, which is fine
         // for us here. However, unaligned accesses will probably make the actual drop
         // implementation fail -- a problem shared by rustc.
@@ -1060,7 +848,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let arg = self.mplace_to_ref(&place)?;
         let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?);
 
-        self.eval_fn_call(
+        self.init_fn_call(
             FnVal::Instance(instance),
             (Abi::Rust, fn_abi),
             &[FnArg::Copy(arg.into())],
@@ -1070,4 +858,118 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             unwind,
         )
     }
+
+    /// Pops the current frame from the stack, copies the return value to the caller, deallocates
+    /// the memory for allocated locals, and jumps to an appropriate place.
+    ///
+    /// If `unwinding` is `false`, then we are performing a normal return
+    /// from a function. In this case, we jump back into the frame of the caller,
+    /// and continue execution as normal.
+    ///
+    /// If `unwinding` is `true`, then we are in the middle of a panic,
+    /// and need to unwind this frame. In this case, we jump to the
+    /// `cleanup` block for the function, which is responsible for running
+    /// `Drop` impls for any locals that have been initialized at this point.
+    /// The cleanup block ends with a special `Resume` terminator, which will
+    /// cause us to continue unwinding.
+    #[instrument(skip(self), level = "trace")]
+    pub(super) fn return_from_current_stack_frame(
+        &mut self,
+        unwinding: bool,
+    ) -> InterpResult<'tcx> {
+        info!(
+            "popping stack frame ({})",
+            if unwinding { "during unwinding" } else { "returning from function" }
+        );
+
+        // Check `unwinding`.
+        assert_eq!(
+            unwinding,
+            match self.frame().loc {
+                Left(loc) => self.body().basic_blocks[loc.block].is_cleanup,
+                Right(_) => true,
+            }
+        );
+        if unwinding && self.frame_idx() == 0 {
+            throw_ub_custom!(fluent::const_eval_unwind_past_top);
+        }
+
+        M::before_stack_pop(self, self.frame())?;
+
+        // Copy return value. Must of course happen *before* we deallocate the locals.
+        // Must be *after* `before_stack_pop` as otherwise the return place might still be protected.
+        let copy_ret_result = if !unwinding {
+            let op = self
+                .local_to_op(mir::RETURN_PLACE, None)
+                .expect("return place should always be live");
+            let dest = self.frame().return_place.clone();
+            let res = if self.stack().len() == 1 {
+                // The initializer of constants and statics will get validated separately
+                // after the constant has been fully evaluated. While we could fall back to the default
+                // code path, that will cause -Zenforce-validity to cycle on static initializers.
+                // Reading from a static's memory is not allowed during its evaluation, and will always
+                // trigger a cycle error. Validation must read from the memory of the current item.
+                // For Miri this means we do not validate the root frame return value,
+                // but Miri anyway calls `read_target_isize` on that so separate validation
+                // is not needed.
+                self.copy_op_no_dest_validation(&op, &dest)
+            } else {
+                self.copy_op_allow_transmute(&op, &dest)
+            };
+            trace!("return value: {:?}", self.dump_place(&dest.into()));
+            // We delay actually short-circuiting on this error until *after* the stack frame is
+            // popped, since we want this error to be attributed to the caller, whose type defines
+            // this transmute.
+            res
+        } else {
+            Ok(())
+        };
+
+        // All right, now it is time to actually pop the frame.
+        let stack_pop_info = self.pop_stack_frame_raw(unwinding)?;
+
+        // Report error from return value copy, if any.
+        copy_ret_result?;
+
+        match stack_pop_info.return_action {
+            ReturnAction::Normal => {}
+            ReturnAction::NoJump => {
+                // The hook already did everything.
+                return Ok(());
+            }
+            ReturnAction::NoCleanup => {
+                // If we are not doing cleanup, also skip everything else.
+                assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
+                assert!(!unwinding, "tried to skip cleanup during unwinding");
+                // Skip machine hook.
+                return Ok(());
+            }
+        }
+
+        // Normal return, figure out where to jump.
+        if unwinding {
+            // Follow the unwind edge.
+            match stack_pop_info.return_to_block {
+                StackPopCleanup::Goto { unwind, .. } => {
+                    // This must be the very last thing that happens, since it can in fact push a new stack frame.
+                    self.unwind_to_block(unwind)
+                }
+                StackPopCleanup::Root { .. } => {
+                    panic!("encountered StackPopCleanup::Root when unwinding!")
+                }
+            }
+        } else {
+            // Follow the normal return edge.
+            match stack_pop_info.return_to_block {
+                StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
+                StackPopCleanup::Root { .. } => {
+                    assert!(
+                        self.stack().is_empty(),
+                        "only the bottommost frame can have StackPopCleanup::Root"
+                    );
+                    Ok(())
+                }
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index b2f07de0ac4..c3d7f2234ed 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -386,7 +386,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx> {
         // A<Struct> -> A<Trait> conversion
         let (src_pointee_ty, dest_pointee_ty) =
-            self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env);
+            self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);
 
         match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
             (&ty::Array(_, length), &ty::Slice(_)) => {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 18d585e4a7a..7a6bbdfdcb5 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1,40 +1,29 @@
-use std::cell::Cell;
-use std::{fmt, mem};
-
-use either::{Either, Left, Right};
+use either::{Left, Right};
 use rustc_errors::DiagCtxtHandle;
 use rustc_hir::def_id::DefId;
-use rustc_hir::definitions::DefPathData;
-use rustc_hir::{self as hir};
-use rustc_index::IndexVec;
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::ObligationCause;
-use rustc_middle::mir::interpret::{
-    CtfeProvenance, ErrorHandled, InvalidMetaKind, ReportedErrorInfo,
-};
+use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
-    self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
-    TyAndLayout,
+    self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
 use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
-use rustc_middle::{bug, mir, span_bug};
-use rustc_mir_dataflow::storage::always_storage_live_locals;
+use rustc_middle::{mir, span_bug};
 use rustc_session::Limit;
 use rustc_span::Span;
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
 use rustc_trait_selection::traits::ObligationCtxt;
-use tracing::{debug, info, info_span, instrument, trace};
+use tracing::{debug, trace};
 
 use super::{
-    err_inval, throw_inval, throw_ub, throw_ub_custom, throw_unsup, GlobalId, Immediate,
-    InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, MemoryKind,
-    OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, Provenance,
-    ReturnAction, Scalar,
+    err_inval, throw_inval, throw_ub, throw_ub_custom, Frame, FrameInfo, GlobalId, InterpErrorInfo,
+    InterpResult, MPlaceTy, Machine, MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic,
+    Projectable, Provenance,
 };
-use crate::{errors, fluent_generated as fluent, util, ReportErrorExt};
+use crate::{fluent_generated as fluent, util, ReportErrorExt};
 
 pub struct InterpCx<'tcx, M: Machine<'tcx>> {
     /// Stores the `Machine` instance.
@@ -57,314 +46,6 @@ pub struct InterpCx<'tcx, M: Machine<'tcx>> {
     pub recursion_limit: Limit,
 }
 
-// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
-// boundary and dropped in the other thread, it would exit the span in the other thread.
-struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>);
-
-impl SpanGuard {
-    /// By default a `SpanGuard` does nothing.
-    fn new() -> Self {
-        Self(tracing::Span::none(), std::marker::PhantomData)
-    }
-
-    /// If a span is entered, we exit the previous span (if any, normally none) and enter the
-    /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of
-    /// `Frame` by creating a dummy span to being with and then entering it once the frame has
-    /// been pushed.
-    fn enter(&mut self, span: tracing::Span) {
-        // This executes the destructor on the previous instance of `SpanGuard`, ensuring that
-        // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we
-        // can't protect the tracing stack, but that'll just lead to weird logging, no actual
-        // problems.
-        *self = Self(span, std::marker::PhantomData);
-        self.0.with_subscriber(|(id, dispatch)| {
-            dispatch.enter(id);
-        });
-    }
-}
-
-impl Drop for SpanGuard {
-    fn drop(&mut self) {
-        self.0.with_subscriber(|(id, dispatch)| {
-            dispatch.exit(id);
-        });
-    }
-}
-
-/// A stack frame.
-pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
-    ////////////////////////////////////////////////////////////////////////////////
-    // Function and callsite information
-    ////////////////////////////////////////////////////////////////////////////////
-    /// The MIR for the function called on this frame.
-    pub body: &'tcx mir::Body<'tcx>,
-
-    /// The def_id and args of the current function.
-    pub instance: ty::Instance<'tcx>,
-
-    /// Extra data for the machine.
-    pub extra: Extra,
-
-    ////////////////////////////////////////////////////////////////////////////////
-    // Return place and locals
-    ////////////////////////////////////////////////////////////////////////////////
-    /// Work to perform when returning from this function.
-    pub return_to_block: StackPopCleanup,
-
-    /// The location where the result of the current stack frame should be written to,
-    /// and its layout in the caller.
-    pub return_place: MPlaceTy<'tcx, Prov>,
-
-    /// The list of locals for this stack frame, stored in order as
-    /// `[return_ptr, arguments..., variables..., temporaries...]`.
-    /// The locals are stored as `Option<Value>`s.
-    /// `None` represents a local that is currently dead, while a live local
-    /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
-    ///
-    /// Do *not* access this directly; always go through the machine hook!
-    pub locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
-
-    /// The span of the `tracing` crate is stored here.
-    /// When the guard is dropped, the span is exited. This gives us
-    /// a full stack trace on all tracing statements.
-    tracing_span: SpanGuard,
-
-    ////////////////////////////////////////////////////////////////////////////////
-    // Current position within the function
-    ////////////////////////////////////////////////////////////////////////////////
-    /// If this is `Right`, we are not currently executing any particular statement in
-    /// this frame (can happen e.g. during frame initialization, and during unwinding on
-    /// frames without cleanup code).
-    ///
-    /// Needs to be public because ConstProp does unspeakable things to it.
-    pub loc: Either<mir::Location, Span>,
-}
-
-/// What we store about a frame in an interpreter backtrace.
-#[derive(Clone, Debug)]
-pub struct FrameInfo<'tcx> {
-    pub instance: ty::Instance<'tcx>,
-    pub span: Span,
-}
-
-#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
-pub enum StackPopCleanup {
-    /// Jump to the next block in the caller, or cause UB if None (that's a function
-    /// that may never return). Also store layout of return place so
-    /// we can validate it at that layout.
-    /// `ret` stores the block we jump to on a normal return, while `unwind`
-    /// stores the block used for cleanup during unwinding.
-    Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
-    /// The root frame of the stack: nowhere else to jump to.
-    /// `cleanup` says whether locals are deallocated. Static computation
-    /// wants them leaked to intern what they need (and just throw away
-    /// the entire `ecx` when it is done).
-    Root { cleanup: bool },
-}
-
-/// Return type of [`InterpCx::pop_stack_frame`].
-pub struct StackPopInfo<'tcx, Prov: Provenance> {
-    /// Additional information about the action to be performed when returning from the popped
-    /// stack frame.
-    pub return_action: ReturnAction,
-
-    /// [`return_to_block`](Frame::return_to_block) of the popped stack frame.
-    pub return_to_block: StackPopCleanup,
-
-    /// [`return_place`](Frame::return_place) of the popped stack frame.
-    pub return_place: MPlaceTy<'tcx, Prov>,
-}
-
-/// State of a local variable including a memoized layout
-#[derive(Clone)]
-pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
-    value: LocalValue<Prov>,
-    /// Don't modify if `Some`, this is only used to prevent computing the layout twice.
-    /// Avoids computing the layout of locals that are never actually initialized.
-    layout: Cell<Option<TyAndLayout<'tcx>>>,
-}
-
-impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("LocalState")
-            .field("value", &self.value)
-            .field("ty", &self.layout.get().map(|l| l.ty))
-            .finish()
-    }
-}
-
-/// Current value of a local variable
-///
-/// This does not store the type of the local; the type is given by `body.local_decls` and can never
-/// change, so by not storing here we avoid having to maintain that as an invariant.
-#[derive(Copy, Clone, Debug)] // Miri debug-prints these
-pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
-    /// This local is not currently alive, and cannot be used at all.
-    Dead,
-    /// A normal, live local.
-    /// Mostly for convenience, we re-use the `Operand` type here.
-    /// This is an optimization over just always having a pointer here;
-    /// we can thus avoid doing an allocation when the local just stores
-    /// immediate values *and* never has its address taken.
-    Live(Operand<Prov>),
-}
-
-impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
-    pub fn make_live_uninit(&mut self) {
-        self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
-    }
-
-    /// This is a hack because Miri needs a way to visit all the provenance in a `LocalState`
-    /// without having a layout or `TyCtxt` available, and we want to keep the `Operand` type
-    /// private.
-    pub fn as_mplace_or_imm(
-        &self,
-    ) -> Option<Either<(Pointer<Option<Prov>>, MemPlaceMeta<Prov>), Immediate<Prov>>> {
-        match self.value {
-            LocalValue::Dead => None,
-            LocalValue::Live(Operand::Indirect(mplace)) => Some(Left((mplace.ptr, mplace.meta))),
-            LocalValue::Live(Operand::Immediate(imm)) => Some(Right(imm)),
-        }
-    }
-
-    /// Read the local's value or error if the local is not yet live or not live anymore.
-    #[inline(always)]
-    pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
-        match &self.value {
-            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
-            LocalValue::Live(val) => Ok(val),
-        }
-    }
-
-    /// Overwrite the local. If the local can be overwritten in place, return a reference
-    /// to do so; otherwise return the `MemPlace` to consult instead.
-    #[inline(always)]
-    pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
-        match &mut self.value {
-            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
-            LocalValue::Live(val) => Ok(val),
-        }
-    }
-}
-
-impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> {
-    pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'tcx, Prov, Extra> {
-        Frame {
-            body: self.body,
-            instance: self.instance,
-            return_to_block: self.return_to_block,
-            return_place: self.return_place,
-            locals: self.locals,
-            loc: self.loc,
-            extra,
-            tracing_span: self.tracing_span,
-        }
-    }
-}
-
-impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
-    /// Get the current location within the Frame.
-    ///
-    /// If this is `Right`, we are not currently executing any particular statement in
-    /// this frame (can happen e.g. during frame initialization, and during unwinding on
-    /// frames without cleanup code).
-    ///
-    /// Used by priroda.
-    pub fn current_loc(&self) -> Either<mir::Location, Span> {
-        self.loc
-    }
-
-    /// Return the `SourceInfo` of the current instruction.
-    pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
-        self.loc.left().map(|loc| self.body.source_info(loc))
-    }
-
-    pub fn current_span(&self) -> Span {
-        match self.loc {
-            Left(loc) => self.body.source_info(loc).span,
-            Right(span) => span,
-        }
-    }
-
-    pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option<hir::HirId> {
-        // We first try to get a HirId via the current source scope,
-        // and fall back to `body.source`.
-        self.current_source_info()
-            .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data {
-                mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
-                mir::ClearCrossCrate::Clear => None,
-            })
-            .or_else(|| {
-                let def_id = self.body.source.def_id().as_local();
-                def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
-            })
-    }
-
-    /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a
-    /// sanity check to detect bugs where we mix up which stack frame a place refers to.
-    #[inline(always)]
-    pub(super) fn locals_addr(&self) -> usize {
-        self.locals.raw.as_ptr().addr()
-    }
-
-    #[must_use]
-    pub fn generate_stacktrace_from_stack(stack: &[Self]) -> Vec<FrameInfo<'tcx>> {
-        let mut frames = Vec::new();
-        // This deliberately does *not* honor `requires_caller_location` since it is used for much
-        // more than just panics.
-        for frame in stack.iter().rev() {
-            let span = match frame.loc {
-                Left(loc) => {
-                    // If the stacktrace passes through MIR-inlined source scopes, add them.
-                    let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
-                    let mut scope_data = &frame.body.source_scopes[scope];
-                    while let Some((instance, call_span)) = scope_data.inlined {
-                        frames.push(FrameInfo { span, instance });
-                        span = call_span;
-                        scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
-                    }
-                    span
-                }
-                Right(span) => span,
-            };
-            frames.push(FrameInfo { span, instance: frame.instance });
-        }
-        trace!("generate stacktrace: {:#?}", frames);
-        frames
-    }
-}
-
-// FIXME: only used by miri, should be removed once translatable.
-impl<'tcx> fmt::Display for FrameInfo<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        ty::tls::with(|tcx| {
-            if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
-                write!(f, "inside closure")
-            } else {
-                // Note: this triggers a `must_produce_diag` state, which means that if we ever
-                // get here we must emit a diagnostic. We should never display a `FrameInfo` unless
-                // we actually want to emit a warning or error to the user.
-                write!(f, "inside `{}`", self.instance)
-            }
-        })
-    }
-}
-
-impl<'tcx> FrameInfo<'tcx> {
-    pub fn as_note(&self, tcx: TyCtxt<'tcx>) -> errors::FrameNote {
-        let span = self.span;
-        if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
-            errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 }
-        } else {
-            let instance = format!("{}", self.instance);
-            // Note: this triggers a `must_produce_diag` state, which means that if we ever get
-            // here we must emit a diagnostic. We should never display a `FrameInfo` unless we
-            // actually want to emit a warning or error to the user.
-            errors::FrameNote { where_: "instance", span, instance, times: 0 }
-        }
-    }
-}
-
 impl<'tcx, M: Machine<'tcx>> HasDataLayout for InterpCx<'tcx, M> {
     #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
@@ -703,30 +384,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         span_bug!(self.cur_span(), "no non-`#[track_caller]` frame found")
     }
 
-    #[inline(always)]
-    pub(super) fn layout_of_local(
-        &self,
-        frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
-        local: mir::Local,
-        layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
-        let state = &frame.locals[local];
-        if let Some(layout) = state.layout.get() {
-            return Ok(layout);
-        }
-
-        let layout = from_known_layout(self.tcx, self.param_env, layout, || {
-            let local_ty = frame.body.local_decls[local].ty;
-            let local_ty =
-                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
-            self.layout_of(local_ty)
-        })?;
-
-        // Layouts of locals are requested a lot, so we cache them.
-        state.layout.set(Some(layout));
-        Ok(layout)
-    }
-
     /// Returns the actual dynamic size and alignment of the place at the given type.
     /// Only the "meta" (metadata) part of the place matters.
     /// This can fail to provide an answer for extern types.
@@ -825,132 +482,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         self.size_and_align_of(&mplace.meta(), &mplace.layout)
     }
 
-    #[instrument(skip(self, body, return_place, return_to_block), level = "debug")]
-    pub fn push_stack_frame(
-        &mut self,
-        instance: ty::Instance<'tcx>,
-        body: &'tcx mir::Body<'tcx>,
-        return_place: &MPlaceTy<'tcx, M::Provenance>,
-        return_to_block: StackPopCleanup,
-    ) -> InterpResult<'tcx> {
-        trace!("body: {:#?}", body);
-
-        // First push a stack frame so we have access to the local args
-        self.push_new_stack_frame(instance, body, return_to_block, return_place.clone())?;
-
-        self.after_stack_frame_push(instance, body)?;
-
-        Ok(())
-    }
-
-    /// Creates a new stack frame, initializes it and pushes it onto the stack.
-    /// A private helper for [`push_stack_frame`](InterpCx::push_stack_frame).
-    fn push_new_stack_frame(
-        &mut self,
-        instance: ty::Instance<'tcx>,
-        body: &'tcx mir::Body<'tcx>,
-        return_to_block: StackPopCleanup,
-        return_place: MPlaceTy<'tcx, M::Provenance>,
-    ) -> InterpResult<'tcx> {
-        let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
-        let locals = IndexVec::from_elem(dead_local, &body.local_decls);
-        let pre_frame = Frame {
-            body,
-            loc: Right(body.span), // Span used for errors caused during preamble.
-            return_to_block,
-            return_place,
-            locals,
-            instance,
-            tracing_span: SpanGuard::new(),
-            extra: (),
-        };
-        let frame = M::init_frame(self, pre_frame)?;
-        self.stack_mut().push(frame);
-
-        Ok(())
-    }
-
-    /// A private helper for [`push_stack_frame`](InterpCx::push_stack_frame).
-    fn after_stack_frame_push(
-        &mut self,
-        instance: ty::Instance<'tcx>,
-        body: &'tcx mir::Body<'tcx>,
-    ) -> InterpResult<'tcx> {
-        // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
-        for &const_ in body.required_consts() {
-            let c =
-                self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
-            c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
-                err.emit_note(*self.tcx);
-                err
-            })?;
-        }
-
-        // done
-        M::after_stack_push(self)?;
-        self.frame_mut().loc = Left(mir::Location::START);
-
-        let span = info_span!("frame", "{}", instance);
-        self.frame_mut().tracing_span.enter(span);
-
-        Ok(())
-    }
-
-    /// Pops a stack frame from the stack and returns some information about it.
-    ///
-    /// This also deallocates locals, if necessary.
-    ///
-    /// [`M::before_stack_pop`] should be called before calling this function.
-    /// [`M::after_stack_pop`] is called by this function automatically.
-    ///
-    /// [`M::before_stack_pop`]: Machine::before_stack_pop
-    /// [`M::after_stack_pop`]: Machine::after_stack_pop
-    pub fn pop_stack_frame(
-        &mut self,
-        unwinding: bool,
-    ) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> {
-        let cleanup = self.cleanup_current_frame_locals()?;
-
-        let frame =
-            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
-
-        let return_to_block = frame.return_to_block;
-        let return_place = frame.return_place.clone();
-
-        let return_action;
-        if cleanup {
-            return_action = M::after_stack_pop(self, frame, unwinding)?;
-            assert_ne!(return_action, ReturnAction::NoCleanup);
-        } else {
-            return_action = ReturnAction::NoCleanup;
-        };
-
-        Ok(StackPopInfo { return_action, return_to_block, return_place })
-    }
-
-    /// A private helper for [`pop_stack_frame`](InterpCx::pop_stack_frame).
-    /// Returns `true` if cleanup has been done, `false` otherwise.
-    fn cleanup_current_frame_locals(&mut self) -> InterpResult<'tcx, bool> {
-        // Cleanup: deallocate locals.
-        // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
-        // We do this while the frame is still on the stack, so errors point to the callee.
-        let return_to_block = self.frame().return_to_block;
-        let cleanup = match return_to_block {
-            StackPopCleanup::Goto { .. } => true,
-            StackPopCleanup::Root { cleanup, .. } => cleanup,
-        };
-
-        if cleanup {
-            // We need to take the locals out, since we need to mutate while iterating.
-            let locals = mem::take(&mut self.frame_mut().locals);
-            for local in &locals {
-                self.deallocate_local(local.value)?;
-            }
-        }
-
-        Ok(cleanup)
-    }
-
     /// Jump to the given block.
     #[inline]
     pub fn go_to_block(&mut self, target: mir::BasicBlock) {
@@ -997,248 +528,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(())
     }
 
-    /// Pops the current frame from the stack, deallocating the
-    /// memory for allocated locals, and jumps to an appropriate place.
-    ///
-    /// If `unwinding` is `false`, then we are performing a normal return
-    /// from a function. In this case, we jump back into the frame of the caller,
-    /// and continue execution as normal.
-    ///
-    /// If `unwinding` is `true`, then we are in the middle of a panic,
-    /// and need to unwind this frame. In this case, we jump to the
-    /// `cleanup` block for the function, which is responsible for running
-    /// `Drop` impls for any locals that have been initialized at this point.
-    /// The cleanup block ends with a special `Resume` terminator, which will
-    /// cause us to continue unwinding.
-    #[instrument(skip(self), level = "debug")]
-    pub(super) fn return_from_current_stack_frame(
-        &mut self,
-        unwinding: bool,
-    ) -> InterpResult<'tcx> {
-        info!(
-            "popping stack frame ({})",
-            if unwinding { "during unwinding" } else { "returning from function" }
-        );
-
-        // Check `unwinding`.
-        assert_eq!(
-            unwinding,
-            match self.frame().loc {
-                Left(loc) => self.body().basic_blocks[loc.block].is_cleanup,
-                Right(_) => true,
-            }
-        );
-        if unwinding && self.frame_idx() == 0 {
-            throw_ub_custom!(fluent::const_eval_unwind_past_top);
-        }
-
-        M::before_stack_pop(self, self.frame())?;
-
-        // Copy return value. Must of course happen *before* we deallocate the locals.
-        let copy_ret_result = if !unwinding {
-            let op = self
-                .local_to_op(mir::RETURN_PLACE, None)
-                .expect("return place should always be live");
-            let dest = self.frame().return_place.clone();
-            let err = if self.stack().len() == 1 {
-                // The initializer of constants and statics will get validated separately
-                // after the constant has been fully evaluated. While we could fall back to the default
-                // code path, that will cause -Zenforce-validity to cycle on static initializers.
-                // Reading from a static's memory is not allowed during its evaluation, and will always
-                // trigger a cycle error. Validation must read from the memory of the current item.
-                // For Miri this means we do not validate the root frame return value,
-                // but Miri anyway calls `read_target_isize` on that so separate validation
-                // is not needed.
-                self.copy_op_no_dest_validation(&op, &dest)
-            } else {
-                self.copy_op_allow_transmute(&op, &dest)
-            };
-            trace!("return value: {:?}", self.dump_place(&dest.into()));
-            // We delay actually short-circuiting on this error until *after* the stack frame is
-            // popped, since we want this error to be attributed to the caller, whose type defines
-            // this transmute.
-            err
-        } else {
-            Ok(())
-        };
-
-        // All right, now it is time to actually pop the frame.
-        let stack_pop_info = self.pop_stack_frame(unwinding)?;
-
-        // Report error from return value copy, if any.
-        copy_ret_result?;
-
-        match stack_pop_info.return_action {
-            ReturnAction::Normal => {}
-            ReturnAction::NoJump => {
-                // The hook already did everything.
-                return Ok(());
-            }
-            ReturnAction::NoCleanup => {
-                // If we are not doing cleanup, also skip everything else.
-                assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
-                assert!(!unwinding, "tried to skip cleanup during unwinding");
-                // Skip machine hook.
-                return Ok(());
-            }
-        }
-
-        // Normal return, figure out where to jump.
-        if unwinding {
-            // Follow the unwind edge.
-            let unwind = match stack_pop_info.return_to_block {
-                StackPopCleanup::Goto { unwind, .. } => unwind,
-                StackPopCleanup::Root { .. } => {
-                    panic!("encountered StackPopCleanup::Root when unwinding!")
-                }
-            };
-            // This must be the very last thing that happens, since it can in fact push a new stack frame.
-            self.unwind_to_block(unwind)
-        } else {
-            // Follow the normal return edge.
-            match stack_pop_info.return_to_block {
-                StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
-                StackPopCleanup::Root { .. } => {
-                    assert!(
-                        self.stack().is_empty(),
-                        "only the topmost frame can have StackPopCleanup::Root"
-                    );
-                    Ok(())
-                }
-            }
-        }
-    }
-
-    /// In the current stack frame, mark all locals as live that are not arguments and don't have
-    /// `Storage*` annotations (this includes the return place).
-    pub fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx> {
-        self.storage_live(mir::RETURN_PLACE)?;
-
-        let body = self.body();
-        let always_live = always_storage_live_locals(body);
-        for local in body.vars_and_temps_iter() {
-            if always_live.contains(local) {
-                self.storage_live(local)?;
-            }
-        }
-        Ok(())
-    }
-
-    pub fn storage_live_dyn(
-        &mut self,
-        local: mir::Local,
-        meta: MemPlaceMeta<M::Provenance>,
-    ) -> InterpResult<'tcx> {
-        trace!("{:?} is now live", local);
-
-        // We avoid `ty.is_trivially_sized` since that does something expensive for ADTs.
-        fn is_very_trivially_sized(ty: Ty<'_>) -> bool {
-            match ty.kind() {
-                ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
-                | ty::Uint(_)
-                | ty::Int(_)
-                | ty::Bool
-                | ty::Float(_)
-                | ty::FnDef(..)
-                | ty::FnPtr(_)
-                | ty::RawPtr(..)
-                | ty::Char
-                | ty::Ref(..)
-                | ty::Coroutine(..)
-                | ty::CoroutineWitness(..)
-                | ty::Array(..)
-                | ty::Closure(..)
-                | ty::CoroutineClosure(..)
-                | ty::Never
-                | ty::Error(_)
-                | ty::Dynamic(_, _, ty::DynStar) => true,
-
-                ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
-
-                ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)),
-
-                ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
-
-                // We don't want to do any queries, so there is not much we can do with ADTs.
-                ty::Adt(..) => false,
-
-                ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
-
-                ty::Infer(ty::TyVar(_)) => false,
-
-                ty::Bound(..)
-                | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-                    bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty)
-                }
-            }
-        }
-
-        // This is a hot function, we avoid computing the layout when possible.
-        // `unsized_` will be `None` for sized types and `Some(layout)` for unsized types.
-        let unsized_ = if is_very_trivially_sized(self.body().local_decls[local].ty) {
-            None
-        } else {
-            // We need the layout.
-            let layout = self.layout_of_local(self.frame(), local, None)?;
-            if layout.is_sized() { None } else { Some(layout) }
-        };
-
-        let local_val = LocalValue::Live(if let Some(layout) = unsized_ {
-            if !meta.has_meta() {
-                throw_unsup!(UnsizedLocal);
-            }
-            // Need to allocate some memory, since `Immediate::Uninit` cannot be unsized.
-            let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?;
-            Operand::Indirect(*dest_place.mplace())
-        } else {
-            assert!(!meta.has_meta()); // we're dropping the metadata
-            // Just make this an efficient immediate.
-            // Note that not calling `layout_of` here does have one real consequence:
-            // if the type is too big, we'll only notice this when the local is actually initialized,
-            // which is a bit too late -- we should ideally notice this already here, when the memory
-            // is conceptually allocated. But given how rare that error is and that this is a hot function,
-            // we accept this downside for now.
-            Operand::Immediate(Immediate::Uninit)
-        });
-
-        // If the local is already live, deallocate its old memory.
-        let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
-        self.deallocate_local(old)?;
-        Ok(())
-    }
-
-    /// Mark a storage as live, killing the previous content.
-    #[inline(always)]
-    pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
-        self.storage_live_dyn(local, MemPlaceMeta::None)
-    }
-
-    pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
-        assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
-        trace!("{:?} is now dead", local);
-
-        // If the local is already dead, this is a NOP.
-        let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
-        self.deallocate_local(old)?;
-        Ok(())
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> {
-        if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
-            // All locals have a backing allocation, even if the allocation is empty
-            // due to the local having ZST type. Hence we can `unwrap`.
-            trace!(
-                "deallocating local {:?}: {:?}",
-                local,
-                // Locals always have a `alloc_id` (they are never the result of a int2ptr).
-                self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
-            );
-            self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
-        };
-        Ok(())
-    }
-
     /// Call a query that can return `ErrorHandled`. Should be used for statics and other globals.
     /// (`mir::Const`/`ty::Const` have `eval` methods that can be used directly instead.)
     pub fn ctfe_query<T>(
@@ -1328,39 +617,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for PlacePrinter<'a, 'tcx, M> {
                 }
                 write!(fmt, ":")?;
 
-                match self.ecx.frame().locals[local].value {
-                    LocalValue::Dead => write!(fmt, " is dead")?,
-                    LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => {
-                        write!(fmt, " is uninitialized")?
-                    }
-                    LocalValue::Live(Operand::Indirect(mplace)) => {
-                        write!(
-                            fmt,
-                            " by {} ref {:?}:",
-                            match mplace.meta {
-                                MemPlaceMeta::Meta(meta) => format!(" meta({meta:?})"),
-                                MemPlaceMeta::None => String::new(),
-                            },
-                            mplace.ptr,
-                        )?;
-                        allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));
-                    }
-                    LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
-                        write!(fmt, " {val:?}")?;
-                        if let Scalar::Ptr(ptr, _size) = val {
-                            allocs.push(ptr.provenance.get_alloc_id());
-                        }
-                    }
-                    LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
-                        write!(fmt, " ({val1:?}, {val2:?})")?;
-                        if let Scalar::Ptr(ptr, _size) = val1 {
-                            allocs.push(ptr.provenance.get_alloc_id());
-                        }
-                        if let Scalar::Ptr(ptr, _size) = val2 {
-                            allocs.push(ptr.provenance.get_alloc_id());
-                        }
-                    }
-                }
+                self.ecx.frame().locals[local].print(&mut allocs, fmt)?;
 
                 write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect()))
             }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 16a0a76a316..9210ec4e16f 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -97,7 +97,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Returns `true` if emulation happened.
     /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own
     /// intrinsic handling.
-    pub fn emulate_intrinsic(
+    pub fn eval_intrinsic(
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, M::Provenance>],
@@ -447,7 +447,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(true)
     }
 
-    pub(super) fn emulate_nondiverging_intrinsic(
+    pub(super) fn eval_nondiverging_intrinsic(
         &mut self,
         intrinsic: &NonDivergingIntrinsic<'tcx>,
     ) -> InterpResult<'tcx> {
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 4620b15d8d9..7af4e0c285b 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -37,7 +37,7 @@ pub enum ReturnAction {
     /// took care of everything.
     NoJump,
 
-    /// Returned by [`InterpCx::pop_stack_frame`] when no cleanup should be done.
+    /// Returned by [`InterpCx::pop_stack_frame_raw`] when no cleanup should be done.
     NoCleanup,
 }
 
@@ -165,6 +165,13 @@ pub trait Machine<'tcx>: Sized {
 
     /// Whether to enforce the validity invariant for a specific layout.
     fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool;
+    /// Whether to enforce the validity invariant *recursively*.
+    fn enforce_validity_recursively(
+        _ecx: &InterpCx<'tcx, Self>,
+        _layout: TyAndLayout<'tcx>,
+    ) -> bool {
+        false
+    }
 
     /// Whether function calls should be [ABI](CallAbi)-checked.
     fn enforce_abi(_ecx: &InterpCx<'tcx, Self>) -> bool {
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index b71e6ed8d2b..2e5d0ae7736 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -1006,8 +1006,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         })
     }
 
-    /// Runs the close in "validation" mode, which means the machine's memory read hooks will be
+    /// Runs the closure in "validation" mode, which means the machine's memory read hooks will be
     /// suppressed. Needless to say, this must only be set with great care! Cannot be nested.
+    ///
+    /// We do this so Miri's allocation access tracking does not show the validation
+    /// reads as spurious accesses.
     pub(super) fn run_for_validation<R>(&self, f: impl FnOnce() -> R) -> R {
         // This deliberately uses `==` on `bool` to follow the pattern
         // `assert!(val.replace(new) == old)`.
diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
index afa2303e387..511756e3f86 100644
--- a/compiler/rustc_const_eval/src/interpret/mod.rs
+++ b/compiler/rustc_const_eval/src/interpret/mod.rs
@@ -1,5 +1,6 @@
 //! An interpreter for MIR used in CTFE and by miri
 
+mod call;
 mod cast;
 mod discriminant;
 mod eval_context;
@@ -11,8 +12,8 @@ mod operand;
 mod operator;
 mod place;
 mod projection;
+mod stack;
 mod step;
-mod terminator;
 mod traits;
 mod util;
 mod validity;
@@ -22,7 +23,8 @@ use eval_context::{from_known_layout, mir_assign_valid_types};
 #[doc(no_inline)]
 pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
 
-pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup};
+pub use self::call::FnArg;
+pub use self::eval_context::{format_interp_error, InterpCx};
 pub use self::intern::{
     intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind,
     InternResult,
@@ -35,7 +37,7 @@ pub use self::operand::{ImmTy, Immediate, OpTy, Readable};
 pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
 use self::place::{MemPlace, Place};
 pub use self::projection::{OffsetMode, Projectable};
-pub use self::terminator::FnArg;
+pub use self::stack::{Frame, FrameInfo, LocalState, StackPopCleanup, StackPopInfo};
 pub(crate) use self::util::create_static_alloc;
 pub use self::validity::{CtfeValidationMode, RefTracking};
 pub use self::visitor::ValueVisitor;
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index d4559e1e8c6..4ced009ab39 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -184,6 +184,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     #[inline]
     pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self {
         debug_assert!(layout.abi.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout");
+        debug_assert_eq!(val.size(), layout.size);
         ImmTy { imm: val.into(), layout }
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index fe5869ad7fa..2f860f9f942 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -1,8 +1,9 @@
 use either::Either;
 use rustc_apfloat::{Float, FloatConvert};
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
+use rustc_middle::mir::NullOp;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, FloatTy, ScalarInt};
+use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::symbol::sym;
 use tracing::trace;
@@ -480,4 +481,38 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
     }
+
+    pub fn nullary_op(
+        &self,
+        null_op: NullOp<'tcx>,
+        arg_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
+        use rustc_middle::mir::NullOp::*;
+
+        let layout = self.layout_of(arg_ty)?;
+        let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap();
+
+        Ok(match null_op {
+            SizeOf => {
+                if !layout.abi.is_sized() {
+                    span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
+                }
+                let val = layout.size.bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            AlignOf => {
+                if !layout.abi.is_sized() {
+                    span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
+                }
+                let val = layout.align.abi.bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            OffsetOf(fields) => {
+                let val =
+                    self.tcx.offset_of_subfield(self.param_env, layout, fields.iter()).bytes();
+                ImmTy::from_uint(val, usize_layout())
+            }
+            UbChecks => ImmTy::from_bool(self.tcx.sess.ub_checks(), *self.tcx),
+        })
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 242f36363a5..470a62026b9 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -572,7 +572,10 @@ where
 
         if M::enforce_validity(self, dest.layout()) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(&dest.to_op(self)?)?;
+            self.validate_operand(
+                &dest.to_op(self)?,
+                M::enforce_validity_recursively(self, dest.layout()),
+            )?;
         }
 
         Ok(())
@@ -811,7 +814,10 @@ where
         // Generally for transmutation, data must be valid both at the old and new type.
         // But if the types are the same, the 2nd validation below suffices.
         if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) {
-            self.validate_operand(&src.to_op(self)?)?;
+            self.validate_operand(
+                &src.to_op(self)?,
+                M::enforce_validity_recursively(self, src.layout()),
+            )?;
         }
 
         // Do the actual copy.
@@ -819,7 +825,10 @@ where
 
         if validate_dest && M::enforce_validity(self, dest.layout()) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(&dest.to_op(self)?)?;
+            self.validate_operand(
+                &dest.to_op(self)?,
+                M::enforce_validity_recursively(self, dest.layout()),
+            )?;
         }
 
         Ok(())
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
new file mode 100644
index 00000000000..50dbced6a2a
--- /dev/null
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -0,0 +1,651 @@
+//! Manages the low-level pushing and popping of stack frames and the (de)allocation of local variables.
+//! For hadling of argument passing and return values, see the `call` module.
+use std::cell::Cell;
+use std::{fmt, mem};
+
+use either::{Either, Left, Right};
+use rustc_hir as hir;
+use rustc_hir::definitions::DefPathData;
+use rustc_index::IndexVec;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, mir};
+use rustc_mir_dataflow::storage::always_storage_live_locals;
+use rustc_span::Span;
+use tracing::{info_span, instrument, trace};
+
+use super::{
+    from_known_layout, throw_ub, throw_unsup, AllocId, CtfeProvenance, Immediate, InterpCx,
+    InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, MemoryKind, Operand, Pointer,
+    Provenance, ReturnAction, Scalar,
+};
+use crate::errors;
+
+// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
+// boundary and dropped in the other thread, it would exit the span in the other thread.
+struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>);
+
+impl SpanGuard {
+    /// By default a `SpanGuard` does nothing.
+    fn new() -> Self {
+        Self(tracing::Span::none(), std::marker::PhantomData)
+    }
+
+    /// If a span is entered, we exit the previous span (if any, normally none) and enter the
+    /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of
+    /// `Frame` by creating a dummy span to being with and then entering it once the frame has
+    /// been pushed.
+    fn enter(&mut self, span: tracing::Span) {
+        // This executes the destructor on the previous instance of `SpanGuard`, ensuring that
+        // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we
+        // can't protect the tracing stack, but that'll just lead to weird logging, no actual
+        // problems.
+        *self = Self(span, std::marker::PhantomData);
+        self.0.with_subscriber(|(id, dispatch)| {
+            dispatch.enter(id);
+        });
+    }
+}
+
+impl Drop for SpanGuard {
+    fn drop(&mut self) {
+        self.0.with_subscriber(|(id, dispatch)| {
+            dispatch.exit(id);
+        });
+    }
+}
+
+/// A stack frame.
+pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
+    ////////////////////////////////////////////////////////////////////////////////
+    // Function and callsite information
+    ////////////////////////////////////////////////////////////////////////////////
+    /// The MIR for the function called on this frame.
+    pub(super) body: &'tcx mir::Body<'tcx>,
+
+    /// The def_id and args of the current function.
+    pub(super) instance: ty::Instance<'tcx>,
+
+    /// Extra data for the machine.
+    pub extra: Extra,
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Return place and locals
+    ////////////////////////////////////////////////////////////////////////////////
+    /// Work to perform when returning from this function.
+    return_to_block: StackPopCleanup,
+
+    /// The location where the result of the current stack frame should be written to,
+    /// and its layout in the caller.
+    pub return_place: MPlaceTy<'tcx, Prov>,
+
+    /// The list of locals for this stack frame, stored in order as
+    /// `[return_ptr, arguments..., variables..., temporaries...]`.
+    /// The locals are stored as `Option<Value>`s.
+    /// `None` represents a local that is currently dead, while a live local
+    /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
+    ///
+    /// Do *not* access this directly; always go through the machine hook!
+    pub locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
+
+    /// The span of the `tracing` crate is stored here.
+    /// When the guard is dropped, the span is exited. This gives us
+    /// a full stack trace on all tracing statements.
+    tracing_span: SpanGuard,
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Current position within the function
+    ////////////////////////////////////////////////////////////////////////////////
+    /// If this is `Right`, we are not currently executing any particular statement in
+    /// this frame (can happen e.g. during frame initialization, and during unwinding on
+    /// frames without cleanup code).
+    ///
+    /// Needs to be public because ConstProp does unspeakable things to it.
+    pub(super) loc: Either<mir::Location, Span>,
+}
+
+#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
+pub enum StackPopCleanup {
+    /// Jump to the next block in the caller, or cause UB if None (that's a function
+    /// that may never return). Also store layout of return place so
+    /// we can validate it at that layout.
+    /// `ret` stores the block we jump to on a normal return, while `unwind`
+    /// stores the block used for cleanup during unwinding.
+    Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
+    /// The root frame of the stack: nowhere else to jump to.
+    /// `cleanup` says whether locals are deallocated. Static computation
+    /// wants them leaked to intern what they need (and just throw away
+    /// the entire `ecx` when it is done).
+    Root { cleanup: bool },
+}
+
+/// Return type of [`InterpCx::pop_stack_frame_raw`].
+pub struct StackPopInfo<'tcx, Prov: Provenance> {
+    /// Additional information about the action to be performed when returning from the popped
+    /// stack frame.
+    pub return_action: ReturnAction,
+
+    /// [`return_to_block`](Frame::return_to_block) of the popped stack frame.
+    pub return_to_block: StackPopCleanup,
+
+    /// [`return_place`](Frame::return_place) of the popped stack frame.
+    pub return_place: MPlaceTy<'tcx, Prov>,
+}
+
+/// State of a local variable including a memoized layout
+#[derive(Clone)]
+pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
+    value: LocalValue<Prov>,
+    /// Don't modify if `Some`, this is only used to prevent computing the layout twice.
+    /// Avoids computing the layout of locals that are never actually initialized.
+    layout: Cell<Option<TyAndLayout<'tcx>>>,
+}
+
+impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("LocalState")
+            .field("value", &self.value)
+            .field("ty", &self.layout.get().map(|l| l.ty))
+            .finish()
+    }
+}
+
+/// Current value of a local variable
+///
+/// This does not store the type of the local; the type is given by `body.local_decls` and can never
+/// change, so by not storing here we avoid having to maintain that as an invariant.
+#[derive(Copy, Clone, Debug)] // Miri debug-prints these
+pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> {
+    /// This local is not currently alive, and cannot be used at all.
+    Dead,
+    /// A normal, live local.
+    /// Mostly for convenience, we re-use the `Operand` type here.
+    /// This is an optimization over just always having a pointer here;
+    /// we can thus avoid doing an allocation when the local just stores
+    /// immediate values *and* never has its address taken.
+    Live(Operand<Prov>),
+}
+
+impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
+    pub fn make_live_uninit(&mut self) {
+        self.value = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
+    }
+
+    /// This is a hack because Miri needs a way to visit all the provenance in a `LocalState`
+    /// without having a layout or `TyCtxt` available, and we want to keep the `Operand` type
+    /// private.
+    pub fn as_mplace_or_imm(
+        &self,
+    ) -> Option<Either<(Pointer<Option<Prov>>, MemPlaceMeta<Prov>), Immediate<Prov>>> {
+        match self.value {
+            LocalValue::Dead => None,
+            LocalValue::Live(Operand::Indirect(mplace)) => Some(Left((mplace.ptr, mplace.meta))),
+            LocalValue::Live(Operand::Immediate(imm)) => Some(Right(imm)),
+        }
+    }
+
+    /// Read the local's value or error if the local is not yet live or not live anymore.
+    #[inline(always)]
+    pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
+        match &self.value {
+            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
+            LocalValue::Live(val) => Ok(val),
+        }
+    }
+
+    /// Overwrite the local. If the local can be overwritten in place, return a reference
+    /// to do so; otherwise return the `MemPlace` to consult instead.
+    #[inline(always)]
+    pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
+        match &mut self.value {
+            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
+            LocalValue::Live(val) => Ok(val),
+        }
+    }
+}
+
+/// What we store about a frame in an interpreter backtrace.
+#[derive(Clone, Debug)]
+pub struct FrameInfo<'tcx> {
+    pub instance: ty::Instance<'tcx>,
+    pub span: Span,
+}
+
+// FIXME: only used by miri, should be removed once translatable.
+impl<'tcx> fmt::Display for FrameInfo<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        ty::tls::with(|tcx| {
+            if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
+                write!(f, "inside closure")
+            } else {
+                // Note: this triggers a `must_produce_diag` state, which means that if we ever
+                // get here we must emit a diagnostic. We should never display a `FrameInfo` unless
+                // we actually want to emit a warning or error to the user.
+                write!(f, "inside `{}`", self.instance)
+            }
+        })
+    }
+}
+
+impl<'tcx> FrameInfo<'tcx> {
+    pub fn as_note(&self, tcx: TyCtxt<'tcx>) -> errors::FrameNote {
+        let span = self.span;
+        if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
+            errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 }
+        } else {
+            let instance = format!("{}", self.instance);
+            // Note: this triggers a `must_produce_diag` state, which means that if we ever get
+            // here we must emit a diagnostic. We should never display a `FrameInfo` unless we
+            // actually want to emit a warning or error to the user.
+            errors::FrameNote { where_: "instance", span, instance, times: 0 }
+        }
+    }
+}
+
+impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> {
+    pub fn with_extra<Extra>(self, extra: Extra) -> Frame<'tcx, Prov, Extra> {
+        Frame {
+            body: self.body,
+            instance: self.instance,
+            return_to_block: self.return_to_block,
+            return_place: self.return_place,
+            locals: self.locals,
+            loc: self.loc,
+            extra,
+            tracing_span: self.tracing_span,
+        }
+    }
+}
+
+impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
+    /// Get the current location within the Frame.
+    ///
+    /// If this is `Right`, we are not currently executing any particular statement in
+    /// this frame (can happen e.g. during frame initialization, and during unwinding on
+    /// frames without cleanup code).
+    ///
+    /// Used by [priroda](https://github.com/oli-obk/priroda).
+    pub fn current_loc(&self) -> Either<mir::Location, Span> {
+        self.loc
+    }
+
+    pub fn body(&self) -> &'tcx mir::Body<'tcx> {
+        self.body
+    }
+
+    pub fn instance(&self) -> ty::Instance<'tcx> {
+        self.instance
+    }
+
+    /// Return the `SourceInfo` of the current instruction.
+    pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
+        self.loc.left().map(|loc| self.body.source_info(loc))
+    }
+
+    pub fn current_span(&self) -> Span {
+        match self.loc {
+            Left(loc) => self.body.source_info(loc).span,
+            Right(span) => span,
+        }
+    }
+
+    pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option<hir::HirId> {
+        // We first try to get a HirId via the current source scope,
+        // and fall back to `body.source`.
+        self.current_source_info()
+            .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data {
+                mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
+                mir::ClearCrossCrate::Clear => None,
+            })
+            .or_else(|| {
+                let def_id = self.body.source.def_id().as_local();
+                def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
+            })
+    }
+
+    /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a
+    /// sanity check to detect bugs where we mix up which stack frame a place refers to.
+    #[inline(always)]
+    pub(super) fn locals_addr(&self) -> usize {
+        self.locals.raw.as_ptr().addr()
+    }
+
+    #[must_use]
+    pub fn generate_stacktrace_from_stack(stack: &[Self]) -> Vec<FrameInfo<'tcx>> {
+        let mut frames = Vec::new();
+        // This deliberately does *not* honor `requires_caller_location` since it is used for much
+        // more than just panics.
+        for frame in stack.iter().rev() {
+            let span = match frame.loc {
+                Left(loc) => {
+                    // If the stacktrace passes through MIR-inlined source scopes, add them.
+                    let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
+                    let mut scope_data = &frame.body.source_scopes[scope];
+                    while let Some((instance, call_span)) = scope_data.inlined {
+                        frames.push(FrameInfo { span, instance });
+                        span = call_span;
+                        scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
+                    }
+                    span
+                }
+                Right(span) => span,
+            };
+            frames.push(FrameInfo { span, instance: frame.instance });
+        }
+        trace!("generate stacktrace: {:#?}", frames);
+        frames
+    }
+}
+
+impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
+    /// Very low-level helper that pushes a stack frame without initializing
+    /// the arguments or local variables.
+    ///
+    /// The high-level version of this is `init_stack_frame`.
+    #[instrument(skip(self, body, return_place, return_to_block), level = "debug")]
+    pub(crate) fn push_stack_frame_raw(
+        &mut self,
+        instance: ty::Instance<'tcx>,
+        body: &'tcx mir::Body<'tcx>,
+        return_place: &MPlaceTy<'tcx, M::Provenance>,
+        return_to_block: StackPopCleanup,
+    ) -> InterpResult<'tcx> {
+        trace!("body: {:#?}", body);
+
+        // We can push a `Root` frame if and only if the stack is empty.
+        debug_assert_eq!(
+            self.stack().is_empty(),
+            matches!(return_to_block, StackPopCleanup::Root { .. })
+        );
+
+        // First push a stack frame so we have access to `instantiate_from_current_frame` and other
+        // `self.frame()`-based functions.
+        let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
+        let locals = IndexVec::from_elem(dead_local, &body.local_decls);
+        let pre_frame = Frame {
+            body,
+            loc: Right(body.span), // Span used for errors caused during preamble.
+            return_to_block,
+            return_place: return_place.clone(),
+            locals,
+            instance,
+            tracing_span: SpanGuard::new(),
+            extra: (),
+        };
+        let frame = M::init_frame(self, pre_frame)?;
+        self.stack_mut().push(frame);
+
+        // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
+        for &const_ in body.required_consts() {
+            let c =
+                self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
+            c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
+                err.emit_note(*self.tcx);
+                err
+            })?;
+        }
+
+        // Finish things up.
+        M::after_stack_push(self)?;
+        self.frame_mut().loc = Left(mir::Location::START);
+        let span = info_span!("frame", "{}", instance);
+        self.frame_mut().tracing_span.enter(span);
+
+        Ok(())
+    }
+
+    /// Low-level helper that pops a stack frame from the stack and returns some information about
+    /// it.
+    ///
+    /// This also deallocates locals, if necessary.
+    ///
+    /// [`M::before_stack_pop`] should be called before calling this function.
+    /// [`M::after_stack_pop`] is called by this function automatically.
+    ///
+    /// The high-level version of this is `return_from_current_stack_frame`.
+    ///
+    /// [`M::before_stack_pop`]: Machine::before_stack_pop
+    /// [`M::after_stack_pop`]: Machine::after_stack_pop
+    pub(super) fn pop_stack_frame_raw(
+        &mut self,
+        unwinding: bool,
+    ) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> {
+        let cleanup = self.cleanup_current_frame_locals()?;
+
+        let frame =
+            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
+
+        let return_to_block = frame.return_to_block;
+        let return_place = frame.return_place.clone();
+
+        let return_action;
+        if cleanup {
+            return_action = M::after_stack_pop(self, frame, unwinding)?;
+            assert_ne!(return_action, ReturnAction::NoCleanup);
+        } else {
+            return_action = ReturnAction::NoCleanup;
+        };
+
+        Ok(StackPopInfo { return_action, return_to_block, return_place })
+    }
+
+    /// A private helper for [`pop_stack_frame_raw`](InterpCx::pop_stack_frame_raw).
+    /// Returns `true` if cleanup has been done, `false` otherwise.
+    fn cleanup_current_frame_locals(&mut self) -> InterpResult<'tcx, bool> {
+        // Cleanup: deallocate locals.
+        // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
+        // We do this while the frame is still on the stack, so errors point to the callee.
+        let return_to_block = self.frame().return_to_block;
+        let cleanup = match return_to_block {
+            StackPopCleanup::Goto { .. } => true,
+            StackPopCleanup::Root { cleanup, .. } => cleanup,
+        };
+
+        if cleanup {
+            // We need to take the locals out, since we need to mutate while iterating.
+            let locals = mem::take(&mut self.frame_mut().locals);
+            for local in &locals {
+                self.deallocate_local(local.value)?;
+            }
+        }
+
+        Ok(cleanup)
+    }
+
+    /// In the current stack frame, mark all locals as live that are not arguments and don't have
+    /// `Storage*` annotations (this includes the return place).
+    pub(crate) fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx> {
+        self.storage_live(mir::RETURN_PLACE)?;
+
+        let body = self.body();
+        let always_live = always_storage_live_locals(body);
+        for local in body.vars_and_temps_iter() {
+            if always_live.contains(local) {
+                self.storage_live(local)?;
+            }
+        }
+        Ok(())
+    }
+
+    pub fn storage_live_dyn(
+        &mut self,
+        local: mir::Local,
+        meta: MemPlaceMeta<M::Provenance>,
+    ) -> InterpResult<'tcx> {
+        trace!("{:?} is now live", local);
+
+        // We avoid `ty.is_trivially_sized` since that does something expensive for ADTs.
+        fn is_very_trivially_sized(ty: Ty<'_>) -> bool {
+            match ty.kind() {
+                ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+                | ty::Uint(_)
+                | ty::Int(_)
+                | ty::Bool
+                | ty::Float(_)
+                | ty::FnDef(..)
+                | ty::FnPtr(_)
+                | ty::RawPtr(..)
+                | ty::Char
+                | ty::Ref(..)
+                | ty::Coroutine(..)
+                | ty::CoroutineWitness(..)
+                | ty::Array(..)
+                | ty::Closure(..)
+                | ty::CoroutineClosure(..)
+                | ty::Never
+                | ty::Error(_)
+                | ty::Dynamic(_, _, ty::DynStar) => true,
+
+                ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
+
+                ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)),
+
+                ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
+
+                // We don't want to do any queries, so there is not much we can do with ADTs.
+                ty::Adt(..) => false,
+
+                ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
+
+                ty::Infer(ty::TyVar(_)) => false,
+
+                ty::Bound(..)
+                | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+                    bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty)
+                }
+            }
+        }
+
+        // This is a hot function, we avoid computing the layout when possible.
+        // `unsized_` will be `None` for sized types and `Some(layout)` for unsized types.
+        let unsized_ = if is_very_trivially_sized(self.body().local_decls[local].ty) {
+            None
+        } else {
+            // We need the layout.
+            let layout = self.layout_of_local(self.frame(), local, None)?;
+            if layout.is_sized() { None } else { Some(layout) }
+        };
+
+        let local_val = LocalValue::Live(if let Some(layout) = unsized_ {
+            if !meta.has_meta() {
+                throw_unsup!(UnsizedLocal);
+            }
+            // Need to allocate some memory, since `Immediate::Uninit` cannot be unsized.
+            let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?;
+            Operand::Indirect(*dest_place.mplace())
+        } else {
+            assert!(!meta.has_meta()); // we're dropping the metadata
+            // Just make this an efficient immediate.
+            // Note that not calling `layout_of` here does have one real consequence:
+            // if the type is too big, we'll only notice this when the local is actually initialized,
+            // which is a bit too late -- we should ideally notice this already here, when the memory
+            // is conceptually allocated. But given how rare that error is and that this is a hot function,
+            // we accept this downside for now.
+            Operand::Immediate(Immediate::Uninit)
+        });
+
+        // If the local is already live, deallocate its old memory.
+        let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
+        self.deallocate_local(old)?;
+        Ok(())
+    }
+
+    /// Mark a storage as live, killing the previous content.
+    #[inline(always)]
+    pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
+        self.storage_live_dyn(local, MemPlaceMeta::None)
+    }
+
+    pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
+        assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
+        trace!("{:?} is now dead", local);
+
+        // If the local is already dead, this is a NOP.
+        let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
+        self.deallocate_local(old)?;
+        Ok(())
+    }
+
+    fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> {
+        if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
+            // All locals have a backing allocation, even if the allocation is empty
+            // due to the local having ZST type. Hence we can `unwrap`.
+            trace!(
+                "deallocating local {:?}: {:?}",
+                local,
+                // Locals always have a `alloc_id` (they are never the result of a int2ptr).
+                self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
+            );
+            self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
+        };
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(super) fn layout_of_local(
+        &self,
+        frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
+        local: mir::Local,
+        layout: Option<TyAndLayout<'tcx>>,
+    ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
+        let state = &frame.locals[local];
+        if let Some(layout) = state.layout.get() {
+            return Ok(layout);
+        }
+
+        let layout = from_known_layout(self.tcx, self.param_env, layout, || {
+            let local_ty = frame.body.local_decls[local].ty;
+            let local_ty =
+                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
+            self.layout_of(local_ty)
+        })?;
+
+        // Layouts of locals are requested a lot, so we cache them.
+        state.layout.set(Some(layout));
+        Ok(layout)
+    }
+}
+
+impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
+    pub(super) fn print(
+        &self,
+        allocs: &mut Vec<Option<AllocId>>,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        match self.value {
+            LocalValue::Dead => write!(fmt, " is dead")?,
+            LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => {
+                write!(fmt, " is uninitialized")?
+            }
+            LocalValue::Live(Operand::Indirect(mplace)) => {
+                write!(
+                    fmt,
+                    " by {} ref {:?}:",
+                    match mplace.meta {
+                        MemPlaceMeta::Meta(meta) => format!(" meta({meta:?})"),
+                        MemPlaceMeta::None => String::new(),
+                    },
+                    mplace.ptr,
+                )?;
+                allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));
+            }
+            LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
+                write!(fmt, " {val:?}")?;
+                if let Scalar::Ptr(ptr, _size) = val {
+                    allocs.push(ptr.provenance.get_alloc_id());
+                }
+            }
+            LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
+                write!(fmt, " ({val1:?}, {val2:?})")?;
+                if let Scalar::Ptr(ptr, _size) = val1 {
+                    allocs.push(ptr.provenance.get_alloc_id());
+                }
+                if let Scalar::Ptr(ptr, _size) = val2 {
+                    allocs.push(ptr.provenance.get_alloc_id());
+                }
+            }
+        }
+
+        Ok(())
+    }
+}
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 211a7b23002..2527eca3446 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -4,16 +4,29 @@
 
 use either::Either;
 use rustc_index::IndexSlice;
-use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::layout::FnAbiOf;
+use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, mir, span_bug};
+use rustc_span::source_map::Spanned;
+use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use tracing::{info, instrument, trace};
 
 use super::{
-    ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, Projectable, Scalar,
+    throw_ub, FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta,
+    PlaceTy, Projectable, Scalar,
 };
 use crate::util;
 
+struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> {
+    callee: FnVal<'tcx, M::ExtraFnVal>,
+    args: Vec<FnArg<'tcx, M::Provenance>>,
+    fn_sig: ty::FnSig<'tcx>,
+    fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
+    /// True if the function is marked as `#[track_caller]` ([`ty::InstanceKind::requires_caller_location`])
+    with_caller_location: bool,
+}
+
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Returns `true` as long as there are more things to do.
     ///
@@ -37,7 +50,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         if let Some(stmt) = basic_block.statements.get(loc.statement_index) {
             let old_frames = self.frame_idx();
-            self.statement(stmt)?;
+            self.eval_statement(stmt)?;
             // Make sure we are not updating `statement_index` of the wrong frame.
             assert_eq!(old_frames, self.frame_idx());
             // Advance the program counter.
@@ -48,7 +61,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         M::before_terminator(self)?;
 
         let terminator = basic_block.terminator();
-        self.terminator(terminator)?;
+        self.eval_terminator(terminator)?;
+        if !self.stack().is_empty() {
+            if let Either::Left(loc) = self.frame().loc {
+                info!("// executing {:?}", loc.block);
+            }
+        }
         Ok(true)
     }
 
@@ -56,7 +74,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// statement counter.
     ///
     /// This does NOT move the statement counter forward, the caller has to do that!
-    pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
+    pub fn eval_statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", stmt);
 
         use rustc_middle::mir::StatementKind::*;
@@ -94,7 +112,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 M::retag_place_contents(self, *kind, &dest)?;
             }
 
-            Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
+            Intrinsic(box intrinsic) => self.eval_nondiverging_intrinsic(intrinsic)?,
 
             // Evaluate the place expression, without reading from it.
             PlaceMention(box place) => {
@@ -179,6 +197,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_immediate(*result, &dest)?;
             }
 
+            NullaryOp(null_op, ty) => {
+                let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
+                let val = self.nullary_op(null_op, ty)?;
+                self.write_immediate(*val, &dest)?;
+            }
+
             Aggregate(box ref kind, ref operands) => {
                 self.write_aggregate(kind, operands, &dest)?;
             }
@@ -230,38 +254,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.write_immediate(*val, &dest)?;
             }
 
-            NullaryOp(ref null_op, ty) => {
-                let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
-                let layout = self.layout_of(ty)?;
-                if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
-                    && layout.is_unsized()
-                {
-                    span_bug!(
-                        self.frame().current_span(),
-                        "{null_op:?} MIR operator called for unsized type {ty}",
-                    );
-                }
-                let val = match null_op {
-                    mir::NullOp::SizeOf => {
-                        let val = layout.size.bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::AlignOf => {
-                        let val = layout.align.abi.bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::OffsetOf(fields) => {
-                        let val = self
-                            .tcx
-                            .offset_of_subfield(self.param_env, layout, fields.iter())
-                            .bytes();
-                        Scalar::from_target_usize(val, self)
-                    }
-                    mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()),
-                };
-                self.write_scalar(val, &dest)?;
-            }
-
             ShallowInitBox(ref operand, _) => {
                 let src = self.eval_operand(operand, None)?;
                 let v = self.read_immediate(&src)?;
@@ -376,16 +368,222 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(())
     }
 
-    /// Evaluate the given terminator. Will also adjust the stack frame and statement position accordingly.
-    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
+    /// Evaluate the arguments of a function call
+    fn eval_fn_call_argument(
+        &self,
+        op: &mir::Operand<'tcx>,
+    ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
+        Ok(match op {
+            mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
+                // Make a regular copy.
+                let op = self.eval_operand(op, None)?;
+                FnArg::Copy(op)
+            }
+            mir::Operand::Move(place) => {
+                // If this place lives in memory, preserve its location.
+                // We call `place_to_op` which will be an `MPlaceTy` whenever there exists
+                // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
+                // which can return a local even if that has an mplace.)
+                let place = self.eval_place(*place)?;
+                let op = self.place_to_op(&place)?;
+
+                match op.as_mplace_or_imm() {
+                    Either::Left(mplace) => FnArg::InPlace(mplace),
+                    Either::Right(_imm) => {
+                        // This argument doesn't live in memory, so there's no place
+                        // to make inaccessible during the call.
+                        // We rely on there not being any stray `PlaceTy` that would let the
+                        // caller directly access this local!
+                        // This is also crucial for tail calls, where we want the `FnArg` to
+                        // stay valid when the old stack frame gets popped.
+                        FnArg::Copy(op)
+                    }
+                }
+            }
+        })
+    }
+
+    /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the
+    /// necessary information about callee and arguments to make a call.
+    fn eval_callee_and_args(
+        &self,
+        terminator: &mir::Terminator<'tcx>,
+        func: &mir::Operand<'tcx>,
+        args: &[Spanned<mir::Operand<'tcx>>],
+    ) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
+        let func = self.eval_operand(func, None)?;
+        let args = args
+            .iter()
+            .map(|arg| self.eval_fn_call_argument(&arg.node))
+            .collect::<InterpResult<'tcx, Vec<_>>>()?;
+
+        let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
+        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
+        let extra_args = &args[fn_sig.inputs().len()..];
+        let extra_args =
+            self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
+
+        let (callee, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
+            ty::FnPtr(_sig) => {
+                let fn_ptr = self.read_pointer(&func)?;
+                let fn_val = self.get_ptr_fn(fn_ptr)?;
+                (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false)
+            }
+            ty::FnDef(def_id, args) => {
+                let instance = self.resolve(def_id, args)?;
+                (
+                    FnVal::Instance(instance),
+                    self.fn_abi_of_instance(instance, extra_args)?,
+                    instance.def.requires_caller_location(*self.tcx),
+                )
+            }
+            _ => {
+                span_bug!(terminator.source_info.span, "invalid callee of type {}", func.layout.ty)
+            }
+        };
+
+        Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location })
+    }
+
+    fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", terminator.kind);
 
-        self.eval_terminator(terminator)?;
-        if !self.stack().is_empty() {
-            if let Either::Left(loc) = self.frame().loc {
-                info!("// executing {:?}", loc.block);
+        use rustc_middle::mir::TerminatorKind::*;
+        match terminator.kind {
+            Return => {
+                self.return_from_current_stack_frame(/* unwinding */ false)?
+            }
+
+            Goto { target } => self.go_to_block(target),
+
+            SwitchInt { ref discr, ref targets } => {
+                let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;
+                trace!("SwitchInt({:?})", *discr);
+
+                // Branch to the `otherwise` case by default, if no match is found.
+                let mut target_block = targets.otherwise();
+
+                for (const_int, target) in targets.iter() {
+                    // Compare using MIR BinOp::Eq, to also support pointer values.
+                    // (Avoiding `self.binary_op` as that does some redundant layout computation.)
+                    let res = self.binary_op(
+                        mir::BinOp::Eq,
+                        &discr,
+                        &ImmTy::from_uint(const_int, discr.layout),
+                    )?;
+                    if res.to_scalar().to_bool()? {
+                        target_block = target;
+                        break;
+                    }
+                }
+
+                self.go_to_block(target_block);
+            }
+
+            Call {
+                ref func,
+                ref args,
+                destination,
+                target,
+                unwind,
+                call_source: _,
+                fn_span: _,
+            } => {
+                let old_stack = self.frame_idx();
+                let old_loc = self.frame().loc;
+
+                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
+                    self.eval_callee_and_args(terminator, func, args)?;
+
+                let destination = self.force_allocation(&self.eval_place(destination)?)?;
+                self.init_fn_call(
+                    callee,
+                    (fn_sig.abi, fn_abi),
+                    &args,
+                    with_caller_location,
+                    &destination,
+                    target,
+                    if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
+                )?;
+                // Sanity-check that `eval_fn_call` either pushed a new frame or
+                // did a jump to another block.
+                if self.frame_idx() == old_stack && self.frame().loc == old_loc {
+                    span_bug!(terminator.source_info.span, "evaluating this call made no progress");
+                }
+            }
+
+            TailCall { ref func, ref args, fn_span: _ } => {
+                let old_frame_idx = self.frame_idx();
+
+                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
+                    self.eval_callee_and_args(terminator, func, args)?;
+
+                self.init_fn_tail_call(callee, (fn_sig.abi, fn_abi), &args, with_caller_location)?;
+
+                if self.frame_idx() != old_frame_idx {
+                    span_bug!(
+                        terminator.source_info.span,
+                        "evaluating this tail call pushed a new stack frame"
+                    );
+                }
+            }
+
+            Drop { place, target, unwind, replace: _ } => {
+                let place = self.eval_place(place)?;
+                let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
+                if let ty::InstanceKind::DropGlue(_, None) = instance.def {
+                    // This is the branch we enter if and only if the dropped type has no drop glue
+                    // whatsoever. This can happen as a result of monomorphizing a drop of a
+                    // generic. In order to make sure that generic and non-generic code behaves
+                    // roughly the same (and in keeping with Mir semantics) we do nothing here.
+                    self.go_to_block(target);
+                    return Ok(());
+                }
+                trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty);
+                self.init_drop_in_place_call(&place, instance, target, unwind)?;
+            }
+
+            Assert { ref cond, expected, ref msg, target, unwind } => {
+                let ignored =
+                    M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
+                let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
+                if ignored || expected == cond_val {
+                    self.go_to_block(target);
+                } else {
+                    M::assert_panic(self, msg, unwind)?;
+                }
+            }
+
+            UnwindTerminate(reason) => {
+                M::unwind_terminate(self, reason)?;
+            }
+
+            // When we encounter Resume, we've finished unwinding
+            // cleanup for the current stack frame. We pop it in order
+            // to continue unwinding the next frame
+            UnwindResume => {
+                trace!("unwinding: resuming from cleanup");
+                // By definition, a Resume terminator means
+                // that we're unwinding
+                self.return_from_current_stack_frame(/* unwinding */ true)?;
+                return Ok(());
+            }
+
+            // It is UB to ever encounter this.
+            Unreachable => throw_ub!(Unreachable),
+
+            // These should never occur for MIR we actually run.
+            FalseEdge { .. } | FalseUnwind { .. } | Yield { .. } | CoroutineDrop => span_bug!(
+                terminator.source_info.span,
+                "{:#?} should have been eliminated by MIR pass",
+                terminator.kind
+            ),
+
+            InlineAsm { template, ref operands, options, ref targets, .. } => {
+                M::eval_inline_asm(self, template, operands, options, targets)?;
             }
         }
+
         Ok(())
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index c8d59c5648d..fadc4ee6c8a 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -155,8 +155,8 @@ impl CtfeValidationMode {
 
 /// State for tracking recursive validation of references
 pub struct RefTracking<T, PATH = ()> {
-    pub seen: FxHashSet<T>,
-    pub todo: Vec<(T, PATH)>,
+    seen: FxHashSet<T>,
+    todo: Vec<(T, PATH)>,
 }
 
 impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
@@ -169,8 +169,11 @@ impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH>
         ref_tracking_for_consts.seen.insert(op);
         ref_tracking_for_consts
     }
+    pub fn next(&mut self) -> Option<(T, PATH)> {
+        self.todo.pop()
+    }
 
-    pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) {
+    fn track(&mut self, op: T, path: impl FnOnce() -> PATH) {
         if self.seen.insert(op.clone()) {
             trace!("Recursing below ptr {:#?}", op);
             let path = path();
@@ -340,7 +343,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         meta: MemPlaceMeta<M::Provenance>,
         pointee: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx> {
-        let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
+        let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.param_env);
         match tail.kind() {
             ty::Dynamic(data, _, ty::Dyn) => {
                 let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
@@ -435,88 +438,96 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? {
             throw_validation_failure!(self.path, NullPtr { ptr_kind })
         }
-        // Do not allow pointers to uninhabited types.
+        // Do not allow references to uninhabited types.
         if place.layout.abi.is_uninhabited() {
             let ty = place.layout.ty;
             throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty })
         }
         // Recursive checking
         if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() {
-            // Determine whether this pointer expects to be pointing to something mutable.
-            let ptr_expected_mutbl = match ptr_kind {
-                PointerKind::Box => Mutability::Mut,
-                PointerKind::Ref(mutbl) => {
-                    // We do not take into account interior mutability here since we cannot know if
-                    // there really is an `UnsafeCell` inside `Option<UnsafeCell>` -- so we check
-                    // that in the recursive descent behind this reference (controlled by
-                    // `allow_immutable_unsafe_cell`).
-                    mutbl
-                }
-            };
             // Proceed recursively even for ZST, no reason to skip them!
             // `!` is a ZST and we want to validate it.
-            if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr(), 0) {
+            if let Some(ctfe_mode) = self.ctfe_mode {
                 let mut skip_recursive_check = false;
-                if let Some(GlobalAlloc::Static(did)) = self.ecx.tcx.try_get_global_alloc(alloc_id)
+                // CTFE imposes restrictions on what references can point to.
+                if let Ok((alloc_id, _offset, _prov)) =
+                    self.ecx.ptr_try_get_alloc_id(place.ptr(), 0)
                 {
-                    let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() };
-                    // Special handling for pointers to statics (irrespective of their type).
-                    assert!(!self.ecx.tcx.is_thread_local_static(did));
-                    assert!(self.ecx.tcx.is_static(did));
-                    // Mode-specific checks
-                    match self.ctfe_mode {
-                        Some(
-                            CtfeValidationMode::Static { .. } | CtfeValidationMode::Promoted { .. },
-                        ) => {
-                            // We skip recursively checking other statics. These statics must be sound by
-                            // themselves, and the only way to get broken statics here is by using
-                            // unsafe code.
-                            // The reasons we don't check other statics is twofold. For one, in all
-                            // sound cases, the static was already validated on its own, and second, we
-                            // trigger cycle errors if we try to compute the value of the other static
-                            // and that static refers back to us (potentially through a promoted).
-                            // This could miss some UB, but that's fine.
-                            // We still walk nested allocations, as they are fundamentally part of this validation run.
-                            // This means we will also recurse into nested statics of *other*
-                            // statics, even though we do not recurse into other statics directly.
-                            // That's somewhat inconsistent but harmless.
-                            skip_recursive_check = !nested;
-                        }
-                        Some(CtfeValidationMode::Const { .. }) => {
-                            // We can't recursively validate `extern static`, so we better reject them.
-                            if self.ecx.tcx.is_foreign_item(did) {
-                                throw_validation_failure!(self.path, ConstRefToExtern);
+                    if let Some(GlobalAlloc::Static(did)) =
+                        self.ecx.tcx.try_get_global_alloc(alloc_id)
+                    {
+                        let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
+                            bug!()
+                        };
+                        // Special handling for pointers to statics (irrespective of their type).
+                        assert!(!self.ecx.tcx.is_thread_local_static(did));
+                        assert!(self.ecx.tcx.is_static(did));
+                        // Mode-specific checks
+                        match ctfe_mode {
+                            CtfeValidationMode::Static { .. }
+                            | CtfeValidationMode::Promoted { .. } => {
+                                // We skip recursively checking other statics. These statics must be sound by
+                                // themselves, and the only way to get broken statics here is by using
+                                // unsafe code.
+                                // The reasons we don't check other statics is twofold. For one, in all
+                                // sound cases, the static was already validated on its own, and second, we
+                                // trigger cycle errors if we try to compute the value of the other static
+                                // and that static refers back to us (potentially through a promoted).
+                                // This could miss some UB, but that's fine.
+                                // We still walk nested allocations, as they are fundamentally part of this validation run.
+                                // This means we will also recurse into nested statics of *other*
+                                // statics, even though we do not recurse into other statics directly.
+                                // That's somewhat inconsistent but harmless.
+                                skip_recursive_check = !nested;
+                            }
+                            CtfeValidationMode::Const { .. } => {
+                                // We can't recursively validate `extern static`, so we better reject them.
+                                if self.ecx.tcx.is_foreign_item(did) {
+                                    throw_validation_failure!(self.path, ConstRefToExtern);
+                                }
                             }
                         }
-                        None => {}
                     }
-                }
 
-                // Dangling and Mutability check.
-                let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id);
-                if alloc_kind == AllocKind::Dead {
-                    // This can happen for zero-sized references. We can't have *any* references to non-existing
-                    // allocations though, interning rejects them all as the rest of rustc isn't happy with them...
-                    // so we throw an error, even though this isn't really UB.
-                    // A potential future alternative would be to resurrect this as a zero-sized allocation
-                    // (which codegen will then compile to an aligned dummy pointer anyway).
-                    throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
-                }
-                // If this allocation has size zero, there is no actual mutability here.
-                if size != Size::ZERO {
-                    let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
-                    // Mutable pointer to immutable memory is no good.
-                    if ptr_expected_mutbl == Mutability::Mut
-                        && alloc_actual_mutbl == Mutability::Not
-                    {
-                        throw_validation_failure!(self.path, MutableRefToImmutable);
+                    // Dangling and Mutability check.
+                    let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id);
+                    if alloc_kind == AllocKind::Dead {
+                        // This can happen for zero-sized references. We can't have *any* references to
+                        // non-existing allocations in const-eval though, interning rejects them all as
+                        // the rest of rustc isn't happy with them... so we throw an error, even though
+                        // this isn't really UB.
+                        // A potential future alternative would be to resurrect this as a zero-sized allocation
+                        // (which codegen will then compile to an aligned dummy pointer anyway).
+                        throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
                     }
-                    // In a const, everything must be completely immutable.
-                    if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
+                    // If this allocation has size zero, there is no actual mutability here.
+                    if size != Size::ZERO {
+                        // Determine whether this pointer expects to be pointing to something mutable.
+                        let ptr_expected_mutbl = match ptr_kind {
+                            PointerKind::Box => Mutability::Mut,
+                            PointerKind::Ref(mutbl) => {
+                                // We do not take into account interior mutability here since we cannot know if
+                                // there really is an `UnsafeCell` inside `Option<UnsafeCell>` -- so we check
+                                // that in the recursive descent behind this reference (controlled by
+                                // `allow_immutable_unsafe_cell`).
+                                mutbl
+                            }
+                        };
+                        // Determine what it actually points to.
+                        let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
+                        // Mutable pointer to immutable memory is no good.
                         if ptr_expected_mutbl == Mutability::Mut
-                            || alloc_actual_mutbl == Mutability::Mut
+                            && alloc_actual_mutbl == Mutability::Not
                         {
-                            throw_validation_failure!(self.path, ConstRefToMutable);
+                            throw_validation_failure!(self.path, MutableRefToImmutable);
+                        }
+                        // In a const, everything must be completely immutable.
+                        if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
+                            if ptr_expected_mutbl == Mutability::Mut
+                                || alloc_actual_mutbl == Mutability::Mut
+                            {
+                                throw_validation_failure!(self.path, ConstRefToMutable);
+                            }
                         }
                     }
                 }
@@ -524,6 +535,15 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 if skip_recursive_check {
                     return Ok(());
                 }
+            } else {
+                // This is not CTFE, so it's Miri with recursive checking.
+                // FIXME: we do *not* check behind boxes, since creating a new box first creates it uninitialized
+                // and then puts the value in there, so briefly we have a box with uninit contents.
+                // FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not
+                // needed since validation reads bypass Stacked Borrows and data race checks.
+                if matches!(ptr_kind, PointerKind::Box) {
+                    return Ok(());
+                }
             }
             let path = &self.path;
             ref_tracking.track(place, || {
@@ -1072,11 +1092,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// `op` is assumed to cover valid memory if it is an indirect operand.
     /// It will error if the bits at the destination do not match the ones described by the layout.
     #[inline(always)]
-    pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
+    pub fn validate_operand(
+        &self,
+        op: &OpTy<'tcx, M::Provenance>,
+        recursive: bool,
+    ) -> InterpResult<'tcx> {
         // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
         // still correct to not use `ctfe_mode`: that mode is for validation of the final constant
-        // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking
-        // recurse through references which, for now, we don't want here, either.
-        self.validate_operand_internal(op, vec![], None, None)
+        // value, it rules out things like `UnsafeCell` in awkward places.
+        if !recursive {
+            return self.validate_operand_internal(op, vec![], None, None);
+        }
+        // Do a recursive check.
+        let mut ref_tracking = RefTracking::empty();
+        self.validate_operand_internal(op, vec![], Some(&mut ref_tracking), None)?;
+        while let Some((mplace, path)) = ref_tracking.todo.pop() {
+            self.validate_operand_internal(&mplace.into(), path, Some(&mut ref_tracking), None)?;
+        }
+        Ok(())
     }
 }
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
index 528274e6aba..5ad55968398 100644
--- a/compiler/rustc_const_eval/src/util/alignment.rs
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -22,7 +22,7 @@ where
     };
 
     let ty = place.ty(local_decls, tcx).ty;
-    let unsized_tail = || tcx.struct_tail_with_normalize(ty, |ty| ty, || {});
+    let unsized_tail = || tcx.struct_tail_for_codegen(ty, param_env);
     match tcx.layout_of(param_env.and(ty)) {
         Ok(layout)
             if layout.align.abi <= pack
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index daf57285ebe..cbd1fdeea2a 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -1,6 +1,6 @@
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
-use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
 use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
 
 use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine};
@@ -30,10 +30,10 @@ pub fn check_validity_requirement<'tcx>(
         return Ok(!layout.abi.is_uninhabited());
     }
 
+    let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
     if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
-        might_permit_raw_init_strict(layout, tcx, kind)
+        might_permit_raw_init_strict(layout, &layout_cx, kind)
     } else {
-        let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
         might_permit_raw_init_lax(layout, &layout_cx, kind)
     }
 }
@@ -42,12 +42,12 @@ pub fn check_validity_requirement<'tcx>(
 /// details.
 fn might_permit_raw_init_strict<'tcx>(
     ty: TyAndLayout<'tcx>,
-    tcx: TyCtxt<'tcx>,
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     kind: ValidityRequirement,
 ) -> Result<bool, &'tcx LayoutError<'tcx>> {
     let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
 
-    let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
+    let mut cx = InterpCx::new(cx.tcx, rustc_span::DUMMY_SP, cx.param_env, machine);
 
     let allocated = cx
         .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
@@ -67,7 +67,7 @@ fn might_permit_raw_init_strict<'tcx>(
     // This does *not* actually check that references are dereferenceable, but since all types that
     // require dereferenceability also require non-null, we don't actually get any false negatives
     // due to this.
-    Ok(cx.validate_operand(&ot).is_ok())
+    Ok(cx.validate_operand(&ot, /*recursive*/ false).is_ok())
 }
 
 /// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index 9a0fd52677d..0f2c0eee27d 100644
--- a/compiler/rustc_data_structures/src/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -51,6 +51,15 @@ impl<T> Steal<T> {
         let value = value_ref.take();
         value.expect("attempt to steal from stolen value")
     }
+
+    /// Writers of rustc drivers often encounter stealing issues. This function makes it possible to
+    /// handle these errors gracefully.
+    ///
+    /// This should not be used within rustc as it leaks information not tracked
+    /// by the query system, breaking incremental compilation.
+    pub fn is_stolen(&self) -> bool {
+        self.value.borrow().is_none()
+    }
 }
 
 impl<CTX, T: HashStable<CTX>> HashStable<CTX> for Steal<T> {
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 627a0ebb4e5..b014fc2dc58 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -51,7 +51,8 @@ use rustc_metadata::creader::MetadataLoader;
 use rustc_metadata::locator;
 use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_session::config::{
-    nightly_options, ErrorOutputType, Input, OutFileName, OutputType, CG_OPTIONS, Z_OPTIONS,
+    nightly_options, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, CG_OPTIONS,
+    Z_OPTIONS,
 };
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
@@ -301,6 +302,8 @@ fn run_compiler(
     let Some(matches) = handle_options(&default_early_dcx, &args) else { return Ok(()) };
 
     let sopts = config::build_session_options(&mut default_early_dcx, &matches);
+    // fully initialize ice path static once unstable options are available as context
+    let ice_file = ice_path_with_config(Some(&sopts.unstable_opts)).clone();
 
     if let Some(ref code) = matches.opt_str("explain") {
         handle_explain(&default_early_dcx, diagnostics_registry(), code, sopts.color);
@@ -315,7 +318,7 @@ fn run_compiler(
         input: Input::File(PathBuf::new()),
         output_file: ofile,
         output_dir: odir,
-        ice_file: ice_path().clone(),
+        ice_file,
         file_loader,
         locale_resources: DEFAULT_LOCALE_RESOURCES,
         lint_caps: Default::default(),
@@ -1306,25 +1309,43 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
 
 static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
 
+// This function should only be called from the ICE hook.
+//
+// The intended behavior is that `run_compiler` will invoke `ice_path_with_config` early in the
+// initialization process to properly initialize the ICE_PATH static based on parsed CLI flags.
+//
+// Subsequent calls to either function will then return the proper ICE path as configured by
+// the environment and cli flags
 fn ice_path() -> &'static Option<PathBuf> {
+    ice_path_with_config(None)
+}
+
+fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<PathBuf> {
+    if ICE_PATH.get().is_some() && config.is_some() && cfg!(debug_assertions) {
+        tracing::warn!(
+            "ICE_PATH has already been initialized -- files may be emitted at unintended paths"
+        )
+    }
+
     ICE_PATH.get_or_init(|| {
         if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
             return None;
         }
-        if let Some(s) = std::env::var_os("RUST_BACKTRACE")
-            && s == "0"
-        {
-            return None;
-        }
         let mut path = match std::env::var_os("RUSTC_ICE") {
             Some(s) => {
                 if s == "0" {
                     // Explicitly opting out of writing ICEs to disk.
                     return None;
                 }
+                if let Some(unstable_opts) = config && unstable_opts.metrics_dir.is_some() {
+                    tracing::warn!("ignoring -Zerror-metrics in favor of RUSTC_ICE for destination of ICE report files");
+                }
                 PathBuf::from(s)
             }
-            None => std::env::current_dir().unwrap_or_default(),
+            None => config
+                .and_then(|unstable_opts| unstable_opts.metrics_dir.to_owned())
+                .or_else(|| std::env::current_dir().ok())
+                .unwrap_or_default(),
         };
         let now: OffsetDateTime = SystemTime::now().into();
         let file_now = now
diff --git a/compiler/rustc_error_codes/src/error_codes/E0517.md b/compiler/rustc_error_codes/src/error_codes/E0517.md
index ae802245bd1..5354a08bf31 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0517.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0517.md
@@ -25,14 +25,17 @@ impl Foo {
 These attributes do not work on typedefs, since typedefs are just aliases.
 
 Representations like `#[repr(u8)]`, `#[repr(i64)]` are for selecting the
-discriminant size for enums with no data fields on any of the variants, e.g.
-`enum Color {Red, Blue, Green}`, effectively setting the size of the enum to
-the size of the provided type. Such an enum can be cast to a value of the same
-type as well. In short, `#[repr(u8)]` makes the enum behave like an integer
-with a constrained set of allowed values.
+discriminant size for enums. For enums with no data fields on any of the
+variants, e.g. `enum Color {Red, Blue, Green}`, this effectively sets the size
+of the enum to the size of the provided type. Such an enum can be cast to a
+value of the same type as well. In short, `#[repr(u8)]` makes a field-less enum
+behave like an integer with a constrained set of allowed values.
 
-Only field-less enums can be cast to numerical primitives, so this attribute
-will not apply to structs.
+For a description of how `#[repr(C)]` and representations like `#[repr(u8)]`
+affect the layout of enums with data fields, see [RFC 2195][rfc2195].
+
+Only field-less enums can be cast to numerical primitives. Representations like
+`#[repr(u8)]` will not apply to structs.
 
 `#[repr(packed)]` reduces padding to make the struct size smaller. The
 representation of enums isn't strictly defined in Rust, and this attribute
@@ -42,3 +45,5 @@ won't work on enums.
 types (i.e., `u8`, `i32`, etc) a representation that permits vectorization via
 SIMD. This doesn't make much sense for enums since they don't consist of a
 single list of data.
+
+[rfc2195]: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index e1dcbf5b280..fae8b5647fc 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -741,6 +741,16 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         self
     }
 
+    #[rustc_lint_diagnostics]
+    pub fn highlighted_span_note(
+        &mut self,
+        span: impl Into<MultiSpan>,
+        msg: Vec<StringPart>,
+    ) -> &mut Self {
+        self.sub_with_highlights(Level::Note, msg, span.into());
+        self
+    }
+
     /// This is like [`Diag::note()`], but it's only printed once.
     #[rustc_lint_diagnostics]
     pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
@@ -815,6 +825,17 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         self
     }
 
+    /// Add a help message attached to this diagnostic with a customizable highlighted message.
+    #[rustc_lint_diagnostics]
+    pub fn highlighted_span_help(
+        &mut self,
+        span: impl Into<MultiSpan>,
+        msg: Vec<StringPart>,
+    ) -> &mut Self {
+        self.sub_with_highlights(Level::Help, msg, span.into());
+        self
+    }
+
     /// Prints the span with some help above it.
     /// This is like [`Diag::help()`], but it gets its own span.
     #[rustc_lint_diagnostics]
@@ -899,8 +920,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         applicability: Applicability,
         style: SuggestionStyle,
     ) -> &mut Self {
-        suggestion.sort_unstable();
-        suggestion.dedup_by(|(s1, m1), (s2, m2)| s1.source_equal(*s2) && m1 == m2);
+        let mut seen = crate::FxHashSet::default();
+        suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
 
         let parts = suggestion
             .into_iter()
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 3e22786a01f..9e3bc3e60b1 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -66,6 +66,7 @@ macro_rules! into_diag_arg_for_number {
             impl IntoDiagArg for $ty {
                 fn into_diag_arg(self) -> DiagArgValue {
                     // Convert to a string if it won't fit into `Number`.
+                    #[allow(irrefutable_let_patterns)]
                     if let Ok(n) = TryInto::<i32>::try_into(self) {
                         DiagArgValue::Number(n)
                     } else {
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 8963b009c31..b8813ea4125 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -43,19 +43,14 @@ const DEFAULT_COLUMN_WIDTH: usize = 140;
 /// Describes the way the content of the `rendered` field of the json output is generated
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum HumanReadableErrorType {
-    Default(ColorConfig),
-    AnnotateSnippet(ColorConfig),
-    Short(ColorConfig),
+    Default,
+    AnnotateSnippet,
+    Short,
 }
 
 impl HumanReadableErrorType {
-    /// Returns a (`short`, `color`) tuple
-    pub fn unzip(self) -> (bool, ColorConfig) {
-        match self {
-            HumanReadableErrorType::Default(cc) => (false, cc),
-            HumanReadableErrorType::Short(cc) => (true, cc),
-            HumanReadableErrorType::AnnotateSnippet(cc) => (false, cc),
-        }
+    pub fn short(&self) -> bool {
+        *self == HumanReadableErrorType::Short
     }
 }
 
@@ -1346,10 +1341,11 @@ impl HumanEmitter {
                 buffer.append(0, ": ", header_style);
                 label_width += 2;
             }
-            for (text, _) in msgs.iter() {
+            let mut line = 0;
+            for (text, style) in msgs.iter() {
                 let text = self.translate_message(text, args).map_err(Report::new).unwrap();
                 // Account for newlines to align output to its label.
-                for (line, text) in normalize_whitespace(&text).lines().enumerate() {
+                for text in normalize_whitespace(&text).lines() {
                     buffer.append(
                         line,
                         &format!(
@@ -1357,8 +1353,38 @@ impl HumanEmitter {
                             if line == 0 { String::new() } else { " ".repeat(label_width) },
                             text
                         ),
-                        header_style,
+                        match style {
+                            Style::Highlight => *style,
+                            _ => header_style,
+                        },
                     );
+                    line += 1;
+                }
+                // We add lines above, but if the last line has no explicit newline (which would
+                // yield an empty line), then we revert one line up to continue with the next
+                // styled text chunk on the same line as the last one from the prior one. Otherwise
+                // every `text` would appear on their own line (because even though they didn't end
+                // in '\n', they advanced `line` by one).
+                if line > 0 {
+                    line -= 1;
+                }
+            }
+            if self.short_message {
+                let labels = msp
+                    .span_labels()
+                    .into_iter()
+                    .filter_map(|label| match label.label {
+                        Some(msg) if label.is_primary => {
+                            let text = self.translate_message(&msg, args).ok()?;
+                            if !text.trim().is_empty() { Some(text.to_string()) } else { None }
+                        }
+                        _ => None,
+                    })
+                    .collect::<Vec<_>>()
+                    .join(", ");
+                if !labels.is_empty() {
+                    buffer.append(line, ": ", Style::NoStyle);
+                    buffer.append(line, &labels, Style::NoStyle);
                 }
             }
         }
@@ -2565,21 +2591,10 @@ fn num_decimal_digits(num: usize) -> usize {
 // We replace some characters so the CLI output is always consistent and underlines aligned.
 // Keep the following list in sync with `rustc_span::char_width`.
 const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
-    ('\t', "    "),    // We do our own tab replacement
-    ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters.
-    ('\u{202A}', "�"), // The following unicode text flow control characters are inconsistently
-    ('\u{202B}', "�"), // supported across CLIs and can cause confusion due to the bytes on disk
-    ('\u{202D}', "�"), // not corresponding to the visible source code, so we replace them always.
-    ('\u{202E}', "�"),
-    ('\u{2066}', "�"),
-    ('\u{2067}', "�"),
-    ('\u{2068}', "�"),
-    ('\u{202C}', "�"),
-    ('\u{2069}', "�"),
     // In terminals without Unicode support the following will be garbled, but in *all* terminals
     // the underlying codepoint will be as well. We could gate this replacement behind a "unicode
     // support" gate.
-    ('\u{0000}', "␀"),
+    ('\0', "␀"),
     ('\u{0001}', "␁"),
     ('\u{0002}', "␂"),
     ('\u{0003}', "␃"),
@@ -2588,11 +2603,12 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
     ('\u{0006}', "␆"),
     ('\u{0007}', "␇"),
     ('\u{0008}', "␈"),
-    ('\u{000B}', "␋"),
-    ('\u{000C}', "␌"),
-    ('\u{000D}', "␍"),
-    ('\u{000E}', "␎"),
-    ('\u{000F}', "␏"),
+    ('\t', "    "), // We do our own tab replacement
+    ('\u{000b}', "␋"),
+    ('\u{000c}', "␌"),
+    ('\u{000d}', "␍"),
+    ('\u{000e}', "␎"),
+    ('\u{000f}', "␏"),
     ('\u{0010}', "␐"),
     ('\u{0011}', "␑"),
     ('\u{0012}', "␒"),
@@ -2603,21 +2619,47 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
     ('\u{0017}', "␗"),
     ('\u{0018}', "␘"),
     ('\u{0019}', "␙"),
-    ('\u{001A}', "␚"),
-    ('\u{001B}', "␛"),
-    ('\u{001C}', "␜"),
-    ('\u{001D}', "␝"),
-    ('\u{001E}', "␞"),
-    ('\u{001F}', "␟"),
-    ('\u{007F}', "␡"),
+    ('\u{001a}', "␚"),
+    ('\u{001b}', "␛"),
+    ('\u{001c}', "␜"),
+    ('\u{001d}', "␝"),
+    ('\u{001e}', "␞"),
+    ('\u{001f}', "␟"),
+    ('\u{007f}', "␡"),
+    ('\u{200d}', ""), // Replace ZWJ for consistent terminal output of grapheme clusters.
+    ('\u{202a}', "�"), // The following unicode text flow control characters are inconsistently
+    ('\u{202b}', "�"), // supported across CLIs and can cause confusion due to the bytes on disk
+    ('\u{202c}', "�"), // not corresponding to the visible source code, so we replace them always.
+    ('\u{202d}', "�"),
+    ('\u{202e}', "�"),
+    ('\u{2066}', "�"),
+    ('\u{2067}', "�"),
+    ('\u{2068}', "�"),
+    ('\u{2069}', "�"),
 ];
 
-fn normalize_whitespace(str: &str) -> String {
-    let mut s = str.to_string();
-    for (c, replacement) in OUTPUT_REPLACEMENTS {
-        s = s.replace(*c, replacement);
+fn normalize_whitespace(s: &str) -> String {
+    const {
+        let mut i = 1;
+        while i < OUTPUT_REPLACEMENTS.len() {
+            assert!(
+                OUTPUT_REPLACEMENTS[i - 1].0 < OUTPUT_REPLACEMENTS[i].0,
+                "The OUTPUT_REPLACEMENTS array must be sorted (for binary search to work) \
+                and must contain no duplicate entries"
+            );
+            i += 1;
+        }
     }
-    s
+    // Scan the input string for a character in the ordered table above.
+    // If it's present, replace it with its alternative string (it can be more than 1 char!).
+    // Otherwise, retain the input char.
+    s.chars().fold(String::with_capacity(s.len()), |mut s, c| {
+        match OUTPUT_REPLACEMENTS.binary_search_by_key(&c, |(k, _)| *k) {
+            Ok(i) => s.push_str(OUTPUT_REPLACEMENTS[i].1),
+            _ => s.push(c),
+        }
+        s
+    })
 }
 
 fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 42a28bc7890..32e59f9ab03 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -55,6 +55,7 @@ pub struct JsonEmitter {
     ignored_directories_in_source_blocks: Vec<String>,
     #[setters(skip)]
     json_rendered: HumanReadableErrorType,
+    color_config: ColorConfig,
     diagnostic_width: Option<usize>,
     macro_backtrace: bool,
     track_diagnostics: bool,
@@ -68,6 +69,7 @@ impl JsonEmitter {
         fallback_bundle: LazyFallbackBundle,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        color_config: ColorConfig,
     ) -> JsonEmitter {
         JsonEmitter {
             dst: IntoDynSyncSend(dst),
@@ -79,6 +81,7 @@ impl JsonEmitter {
             ui_testing: false,
             ignored_directories_in_source_blocks: Vec::new(),
             json_rendered,
+            color_config,
             diagnostic_width: None,
             macro_backtrace: false,
             track_diagnostics: false,
@@ -173,7 +176,7 @@ impl Emitter for JsonEmitter {
     }
 
     fn should_show_explain(&self) -> bool {
-        !matches!(self.json_rendered, HumanReadableErrorType::Short(_))
+        !self.json_rendered.short()
     }
 }
 
@@ -353,8 +356,8 @@ impl Diagnostic {
 
         let buf = BufWriter::default();
         let mut dst: Destination = Box::new(buf.clone());
-        let (short, color_config) = je.json_rendered.unzip();
-        match color_config {
+        let short = je.json_rendered.short();
+        match je.color_config {
             ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)),
             ColorConfig::Never => {}
         }
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index e3549fc3aa5..6af376d7afd 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -50,7 +50,8 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
             sm,
             fallback_bundle,
             true, // pretty
-            HumanReadableErrorType::Short(ColorConfig::Never),
+            HumanReadableErrorType::Short,
+            ColorConfig::Never,
         );
 
         let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 6ce9ff18c27..628c6bfeb79 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -3,34 +3,32 @@ use std::borrow::Cow;
 use rustc_ast::token::{self, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, Diag, DiagMessage};
+use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
 use rustc_macros::Subdiagnostic;
 use rustc_parse::parser::{Parser, Recovery};
+use rustc_session::parse::ParseSess;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Ident;
 use rustc_span::{ErrorGuaranteed, Span};
 use tracing::debug;
 
 use super::macro_rules::{parser_from_cx, NoopTracker};
-use crate::base::{DummyResult, ExtCtxt, MacResult};
 use crate::expand::{parse_ast_fragment, AstFragmentKind};
 use crate::mbe::macro_parser::ParseResult::*;
 use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser};
 use crate::mbe::macro_rules::{try_match_macro, Tracker};
 
-pub(super) fn failed_to_match_macro<'cx>(
-    cx: &'cx mut ExtCtxt<'_>,
+pub(super) fn failed_to_match_macro(
+    psess: &ParseSess,
     sp: Span,
     def_span: Span,
     name: Ident,
     arg: TokenStream,
     lhses: &[Vec<MatcherLoc>],
-) -> Box<dyn MacResult + 'cx> {
-    let psess = &cx.sess.psess;
-
+) -> (Span, ErrorGuaranteed) {
     // An error occurred, try the expansion again, tracking the expansion closely for better
     // diagnostics.
-    let mut tracker = CollectTrackerAndEmitter::new(cx, sp);
+    let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
 
     let try_success_result = try_match_macro(psess, name, &arg, lhses, &mut tracker);
 
@@ -38,7 +36,7 @@ pub(super) fn failed_to_match_macro<'cx>(
         // Nonterminal parser recovery might turn failed matches into successful ones,
         // but for that it must have emitted an error already
         assert!(
-            tracker.cx.dcx().has_errors().is_some(),
+            tracker.dcx.has_errors().is_some(),
             "Macro matching returned a success on the second try"
         );
     }
@@ -50,15 +48,15 @@ pub(super) fn failed_to_match_macro<'cx>(
 
     let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
     else {
-        return DummyResult::any(sp, cx.dcx().span_delayed_bug(sp, "failed to match a macro"));
+        return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro"));
     };
 
     let span = token.span.substitute_dummy(sp);
 
-    let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token, None));
+    let mut err = psess.dcx().struct_span_err(span, parse_failure_msg(&token, None));
     err.span_label(span, label);
-    if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
-        err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
+    if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
+        err.span_label(psess.source_map().guess_head_span(def_span), "when calling this macro");
     }
 
     annotate_doc_comment(&mut err, psess.source_map(), span);
@@ -76,7 +74,7 @@ pub(super) fn failed_to_match_macro<'cx>(
         err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
         err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
 
-        if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
+        if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
             err.help("try using `:tt` instead in the macro definition");
         }
     }
@@ -104,18 +102,17 @@ pub(super) fn failed_to_match_macro<'cx>(
         }
     }
     let guar = err.emit();
-    cx.trace_macros_diag();
-    DummyResult::any(sp, guar)
+    (sp, guar)
 }
 
 /// The tracker used for the slow error path that collects useful info for diagnostics.
-struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
-    cx: &'a mut ExtCtxt<'cx>,
+struct CollectTrackerAndEmitter<'dcx, 'matcher> {
+    dcx: DiagCtxtHandle<'dcx>,
     remaining_matcher: Option<&'matcher MatcherLoc>,
     /// Which arm's failure should we report? (the one furthest along)
     best_failure: Option<BestFailure>,
     root_span: Span,
-    result: Option<Box<dyn MacResult + 'cx>>,
+    result: Option<(Span, ErrorGuaranteed)>,
 }
 
 struct BestFailure {
@@ -131,7 +128,7 @@ impl BestFailure {
     }
 }
 
-impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
+impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'matcher> {
     type Failure = (Token, u32, &'static str);
 
     fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure {
@@ -151,7 +148,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
             Success(_) => {
                 // Nonterminal parser recovery might turn failed matches into successful ones,
                 // but for that it must have emitted an error already
-                self.cx.dcx().span_delayed_bug(
+                self.dcx.span_delayed_bug(
                     self.root_span,
                     "should not collect detailed info for successful macro match",
                 );
@@ -177,10 +174,10 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
             }
             Error(err_sp, msg) => {
                 let span = err_sp.substitute_dummy(self.root_span);
-                let guar = self.cx.dcx().span_err(span, msg.clone());
-                self.result = Some(DummyResult::any(span, guar));
+                let guar = self.dcx.span_err(span, msg.clone());
+                self.result = Some((span, guar));
             }
-            ErrorReported(guar) => self.result = Some(DummyResult::any(self.root_span, *guar)),
+            ErrorReported(guar) => self.result = Some((self.root_span, *guar)),
         }
     }
 
@@ -193,9 +190,9 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
     }
 }
 
-impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> {
-    fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self {
-        Self { cx, remaining_matcher: None, best_failure: None, root_span, result: None }
+impl<'dcx> CollectTrackerAndEmitter<'dcx, '_> {
+    fn new(dcx: DiagCtxtHandle<'dcx>, root_span: Span) -> Self {
+        Self { dcx, remaining_matcher: None, best_failure: None, root_span, result: None }
     }
 }
 
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 1502177563d..6f177107e70 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -268,7 +268,10 @@ fn expand_macro<'cx>(
         }
         Err(CanRetry::Yes) => {
             // Retry and emit a better error.
-            diagnostics::failed_to_match_macro(cx, sp, def_span, name, arg, lhses)
+            let (span, guar) =
+                diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, lhses);
+            cx.trace_macros_diag();
+            DummyResult::any(span, guar)
         }
     }
 }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 9684fe10510..44286cfeeef 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -267,6 +267,8 @@ declare_features! (
     (accepted, min_const_generics, "1.51.0", Some(74878)),
     /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions.
     (accepted, min_const_unsafe_fn, "1.33.0", Some(55607)),
+    /// Allows exhaustive pattern matching on uninhabited types when matched by value.
+    (accepted, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", Some(119612)),
     /// Allows using `Self` and associated types in struct expressions and patterns.
     (accepted, more_struct_aliases, "1.16.0", Some(37544)),
     /// Allows using the MOVBE target feature.
@@ -390,6 +392,8 @@ declare_features! (
     (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208)),
     /// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block.
     (accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668)),
+    /// Allows unsafe on extern declarations and safety qualifiers over internal items.
+    (accepted, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)),
     /// Allows importing and reexporting macros with `use`,
     /// enables macro modularization in general.
     (accepted, use_extern_macros, "1.30.0", Some(35896)),
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index ef03a25bc16..72ea55d5999 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -703,21 +703,21 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::No, allocator_internals, experimental!(needs_allocator),
     ),
     gated!(
-        panic_runtime, Normal, template!(Word), WarnFollowing,
+        panic_runtime, CrateLevel, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, experimental!(panic_runtime)
     ),
     gated!(
-        needs_panic_runtime, Normal, template!(Word), WarnFollowing,
+        needs_panic_runtime, CrateLevel, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, experimental!(needs_panic_runtime)
     ),
     gated!(
-        compiler_builtins, Normal, template!(Word), WarnFollowing,
+        compiler_builtins, CrateLevel, template!(Word), WarnFollowing,
         EncodeCrossCrate::No,
         "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
         which contains compiler-rt intrinsics and will never be stable",
     ),
     gated!(
-        profiler_runtime, Normal, template!(Word), WarnFollowing,
+        profiler_runtime, CrateLevel, template!(Word), WarnFollowing,
         EncodeCrossCrate::No,
         "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
         which contains the profiler runtime and will never be stable",
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index f665dc71411..b7f0ed5afce 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -82,6 +82,9 @@ declare_features! (
     /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
     (removed, custom_derive, "1.32.0", Some(29644),
      Some("subsumed by `#[proc_macro_derive]`")),
+    /// Allows default type parameters to influence type inference.
+    (removed, default_type_parameter_fallback, "CURRENT_RUSTC_VERSION", Some(27336),
+     Some("never properly implemented; requires significant design work")),
     /// Allows using `#[doc(keyword = "...")]`.
     (removed, doc_keyword, "1.28.0", Some(51315),
      Some("merged into `#![feature(rustdoc_internals)]`")),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 03210085a12..47810bc9165 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -431,8 +431,6 @@ declare_features! (
     (unstable, custom_test_frameworks, "1.30.0", Some(50297)),
     /// Allows declarative macros 2.0 (`macro`).
     (unstable, decl_macro, "1.17.0", Some(39412)),
-    /// Allows default type parameters to influence type inference.
-    (unstable, default_type_parameter_fallback, "1.3.0", Some(27336)),
     /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait
     (unstable, deprecated_safe, "1.61.0", Some(94978)),
     /// Allows having using `suggestion` in the `#[deprecated]` attribute.
@@ -521,9 +519,6 @@ declare_features! (
     (unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)),
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
     (unstable, marker_trait_attr, "1.30.0", Some(29864)),
-    /// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are
-    /// unambiguously sound.
-    (unstable, min_exhaustive_patterns, "1.77.0", Some(119612)),
     /// A minimal, sound subset of specialization intended to be used by the
     /// standard library until the soundness issues with specialization
     /// are fixed.
@@ -591,6 +586,8 @@ declare_features! (
     (incomplete, return_type_notation, "1.70.0", Some(109417)),
     /// Allows `extern "rust-cold"`.
     (unstable, rust_cold_cc, "1.63.0", Some(97544)),
+    /// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
+    (unstable, sha512_sm_x86, "CURRENT_RUSTC_VERSION", Some(126624)),
     /// Shortern the tail expression lifetime
     (unstable, shorter_tail_lifetimes, "1.79.0", Some(123739)),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
@@ -629,8 +626,6 @@ declare_features! (
     (incomplete, unnamed_fields, "1.74.0", Some(49804)),
     /// Allows unsafe attributes.
     (unstable, unsafe_attributes, "1.80.0", Some(123757)),
-    /// Allows unsafe on extern declarations and safety qualifiers over internal items.
-    (unstable, unsafe_extern_blocks, "1.80.0", Some(123743)),
     /// Allows const generic parameters to be defined with types that
     /// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
     (incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 3b9aea08791..33e8432596b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2952,6 +2952,17 @@ pub struct FnDecl<'hir> {
     pub lifetime_elision_allowed: bool,
 }
 
+impl<'hir> FnDecl<'hir> {
+    pub fn opt_delegation_sig_id(&self) -> Option<DefId> {
+        if let FnRetTy::Return(ty) = self.output
+            && let TyKind::InferDelegation(sig_id, _) = ty.kind
+        {
+            return Some(sig_id);
+        }
+        None
+    }
+}
+
 /// Represents what type of implicit self a function has, if any.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum ImplicitSelfKind {
@@ -3689,6 +3700,11 @@ impl<'hir> OwnerNode<'hir> {
         }
     }
 
+    /// Check if node is an impl block.
+    pub fn is_impl_block(&self) -> bool {
+        matches!(self, OwnerNode::Item(Item { kind: ItemKind::Impl(_), .. }))
+    }
+
     expect_methods_self! {
         expect_item,         &'hir Item<'hir>,        OwnerNode::Item(n),        n;
         expect_foreign_item, &'hir ForeignItem<'hir>, OwnerNode::ForeignItem(n), n;
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 53cde14f337..35577613800 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1117,7 +1117,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
             .dcx()
             .create_err(LifetimesOrBoundsMismatchOnTrait {
                 span,
-                item_kind: assoc_item_kind_str(&impl_m),
+                item_kind: impl_m.descr(),
                 ident: impl_m.ident(tcx),
                 generics_span,
                 bounds_span,
@@ -1294,7 +1294,7 @@ fn compare_number_of_generics<'tcx>(
         ("const", trait_own_counts.consts, impl_own_counts.consts),
     ];
 
-    let item_kind = assoc_item_kind_str(&impl_);
+    let item_kind = impl_.descr();
 
     let mut err_occurred = None;
     for (kind, trait_count, impl_count) in matchings {
@@ -1676,7 +1676,7 @@ fn compare_generic_param_kinds<'tcx>(
                 param_impl_span,
                 E0053,
                 "{} `{}` has an incompatible generic parameter for trait `{}`",
-                assoc_item_kind_str(&impl_item),
+                impl_item.descr(),
                 trait_item.name,
                 &tcx.def_path_str(tcx.parent(trait_item.def_id))
             );
@@ -2249,14 +2249,6 @@ fn param_env_with_gat_bounds<'tcx>(
     ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
 }
 
-fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
-    match impl_item.kind {
-        ty::AssocKind::Const => "const",
-        ty::AssocKind::Fn => "method",
-        ty::AssocKind::Type => "type",
-    }
-}
-
 /// Manually check here that `async fn foo()` wasn't matched against `fn foo()`,
 /// and extract a better error if so.
 fn try_report_async_mismatch<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 2e965c59ebb..847a1e64706 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -2,7 +2,7 @@ use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::{self as hir, LangItem};
 use rustc_middle::bug;
-use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
+use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Symbol;
@@ -455,32 +455,22 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         );
                     }
                 }
-                // No special checking is needed for these:
-                // - Typeck has checked that Const operands are integers.
-                // - AST lowering guarantees that SymStatic points to a static.
-                hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymStatic { .. } => {}
-                // Check that sym actually points to a function. Later passes
-                // depend on this.
+                // Typeck has checked that Const operands are integers.
+                hir::InlineAsmOperand::Const { anon_const } => {
+                    debug_assert!(matches!(
+                        self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
+                        ty::Error(_) | ty::Int(_) | ty::Uint(_)
+                    ));
+                }
+                // Typeck has checked that SymFn refers to a function.
                 hir::InlineAsmOperand::SymFn { anon_const } => {
-                    let ty = self.tcx.type_of(anon_const.def_id).instantiate_identity();
-                    match ty.kind() {
-                        ty::Never | ty::Error(_) => {}
-                        ty::FnDef(..) => {}
-                        _ => {
-                            self.tcx
-                                .dcx()
-                                .struct_span_err(*op_sp, "invalid `sym` operand")
-                                .with_span_label(
-                                    self.tcx.def_span(anon_const.def_id),
-                                    format!("is {} `{}`", ty.kind().article(), ty),
-                                )
-                                .with_help(
-                                    "`sym` operands must refer to either a function or a static",
-                                )
-                                .emit();
-                        }
-                    };
+                    debug_assert!(matches!(
+                        self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
+                        ty::Error(_) | ty::FnDef(..)
+                    ));
                 }
+                // AST lowering guarantees that SymStatic points to a static.
+                hir::InlineAsmOperand::SymStatic { .. } => {}
                 // No special checking is needed for labels.
                 hir::InlineAsmOperand::Label { .. } => {}
             }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index c878095ba0d..a9f8630741a 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1276,7 +1276,7 @@ fn check_item_type(
             UnsizedHandling::Forbid => true,
             UnsizedHandling::Allow => false,
             UnsizedHandling::AllowIfForeignTail => {
-                let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
+                let tail = tcx.struct_tail_for_codegen(item_ty, wfcx.param_env);
                 !matches!(tail.kind(), ty::Foreign(_))
             }
         };
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 47ff748547a..8c1e5e78b75 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -67,6 +67,7 @@ pub fn provide(providers: &mut Providers) {
         item_super_predicates: item_bounds::item_super_predicates,
         explicit_item_super_predicates: item_bounds::explicit_item_super_predicates,
         item_non_self_assumptions: item_bounds::item_non_self_assumptions,
+        impl_super_outlives: item_bounds::impl_super_outlives,
         generics_of: generics_of::generics_of,
         predicates_of: predicates_of::predicates_of,
         predicates_defined_on,
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 80a65aa2988..60e2c2eb30e 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -54,13 +54,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
         };
     }
 
-    // For a delegation item inherit generics from callee.
-    if let Some(sig_id) = tcx.hir().opt_delegation_sig_id(def_id)
-        && let Some(generics) = inherit_generics_for_delegation_item(tcx, def_id, sig_id)
-    {
-        return generics;
-    }
-
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
     let node = tcx.hir_node(hir_id);
@@ -234,6 +227,16 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 // inherit the generics of the item.
                 Some(parent.to_def_id())
             }
+            ItemKind::Fn(sig, _, _) => {
+                // For a delegation item inherit generics from callee.
+                if let Some(sig_id) = sig.decl.opt_delegation_sig_id()
+                    && let Some(generics) =
+                        inherit_generics_for_delegation_item(tcx, def_id, sig_id)
+                {
+                    return generics;
+                }
+                None
+            }
             _ => None,
         },
         _ => None,
@@ -335,8 +338,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
             if default.is_some() {
                 match allow_defaults {
                     Defaults::Allowed => {}
-                    Defaults::FutureCompatDisallowed
-                        if tcx.features().default_type_parameter_fallback => {}
                     Defaults::FutureCompatDisallowed => {
                         tcx.node_span_lint(
                             lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 6bff99ea65f..ec48c781c0e 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -212,6 +212,8 @@ pub(super) fn item_super_predicates(
     })
 }
 
+/// This exists as an optimization to compute only the item bounds of the item
+/// that are not `Self` bounds.
 pub(super) fn item_non_self_assumptions(
     tcx: TyCtxt<'_>,
     def_id: DefId,
@@ -226,6 +228,25 @@ pub(super) fn item_non_self_assumptions(
     }
 }
 
+/// This exists as an optimization to compute only the supertraits of this impl's
+/// trait that are outlives bounds.
+pub(super) fn impl_super_outlives(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
+    tcx.impl_trait_header(def_id).expect("expected an impl of trait").trait_ref.map_bound(
+        |trait_ref| {
+            let clause: ty::Clause<'_> = trait_ref.upcast(tcx);
+            tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter(|clause| {
+                matches!(
+                    clause.kind().skip_binder(),
+                    ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_)
+                )
+            }))
+        },
+    )
+}
+
 struct AssocTyToOpaque<'tcx> {
     tcx: TyCtxt<'tcx>,
     fn_def_id: DefId,
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index ae52dbd56f9..a5a56cb845d 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -115,13 +115,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         None => {}
     }
 
-    // For a delegation item inherit predicates from callee.
-    if let Some(sig_id) = tcx.hir().opt_delegation_sig_id(def_id)
-        && let Some(predicates) = inherit_predicates_for_delegation_item(tcx, def_id, sig_id)
-    {
-        return predicates;
-    }
-
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let node = tcx.hir_node(hir_id);
 
@@ -151,6 +144,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => {
                 is_trait = Some(self_bounds);
             }
+
+            ItemKind::Fn(sig, _, _) => {
+                // For a delegation item inherit predicates from callee.
+                if let Some(sig_id) = sig.decl.opt_delegation_sig_id()
+                    && let Some(predicates) =
+                        inherit_predicates_for_delegation_item(tcx, def_id, sig_id)
+                {
+                    return predicates;
+                }
+            }
             _ => {}
         }
     };
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 592a3cb5526..8cb4ba6c669 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -7,7 +7,7 @@ use rustc_hir::HirId;
 use rustc_middle::query::plumbing::CyclePlaceholder;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
@@ -34,6 +34,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
     let parent_node_id = tcx.parent_hir_id(hir_id);
     let parent_node = tcx.hir_node(parent_node_id);
 
+    let find_sym_fn = |&(op, op_sp)| match op {
+        hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == hir_id => {
+            Some((anon_const, op_sp))
+        }
+        _ => None,
+    };
+
+    let find_const = |&(op, op_sp)| match op {
+        hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
+            Some((anon_const, op_sp))
+        }
+        _ => None,
+    };
+
     match parent_node {
         // Anon consts "inside" the type system.
         Node::ConstArg(&ConstArg {
@@ -45,13 +59,51 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
         // Anon consts outside the type system.
         Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
         | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
-            if asm.operands.iter().any(|(op, _op_sp)| match op {
-                hir::InlineAsmOperand::Const { anon_const }
-                | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
-                _ => false,
-            }) =>
+            if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_sym_fn) =>
         {
-            tcx.typeck(def_id).node_type(hir_id)
+            let ty = tcx.typeck(def_id).node_type(hir_id);
+
+            match ty.kind() {
+                ty::Error(_) => ty,
+                ty::FnDef(..) => ty,
+                _ => {
+                    let guar = tcx
+                        .dcx()
+                        .struct_span_err(op_sp, "invalid `sym` operand")
+                        .with_span_label(
+                            tcx.def_span(anon_const.def_id),
+                            format!("is {} `{}`", ty.kind().article(), ty),
+                        )
+                        .with_help("`sym` operands must refer to either a function or a static")
+                        .emit();
+
+                    Ty::new_error(tcx, guar)
+                }
+            }
+        }
+        Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
+        | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
+            if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
+        {
+            let ty = tcx.typeck(def_id).node_type(hir_id);
+
+            match ty.kind() {
+                ty::Error(_) => ty,
+                ty::Int(_) | ty::Uint(_) => ty,
+                _ => {
+                    let guar = tcx
+                        .dcx()
+                        .struct_span_err(op_sp, "invalid type for `const` operand")
+                        .with_span_label(
+                            tcx.def_span(anon_const.def_id),
+                            format!("is {} `{}`", ty.kind().article(), ty),
+                        )
+                        .with_help("`const` operands must be of an integer type")
+                        .emit();
+
+                    Ty::new_error(tcx, guar)
+                }
+            }
         }
         Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
             tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index e21ed55bce3..ca62ef92b83 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -242,7 +242,7 @@ pub(crate) fn inherit_sig_for_delegation_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
 ) -> &'tcx [Ty<'tcx>] {
-    let sig_id = tcx.hir().delegation_sig_id(def_id);
+    let sig_id = tcx.hir().opt_delegation_sig_id(def_id).unwrap();
     let caller_sig = tcx.fn_sig(sig_id);
     if let Err(err) = check_constraints(tcx, def_id, sig_id) {
         let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1;
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index f18224c39ae..a59e9aa85fd 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -253,32 +253,6 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
             match (args_iter.peek(), params.peek()) {
                 (Some(&arg), Some(&param)) => {
                     match (arg, &param.kind, arg_count.explicit_late_bound) {
-                        (
-                            GenericArg::Const(hir::ConstArg {
-                                is_desugared_from_effects: true,
-                                ..
-                            }),
-                            GenericParamDefKind::Const { is_host_effect: false, .. }
-                            | GenericParamDefKind::Type { .. }
-                            | GenericParamDefKind::Lifetime,
-                            _,
-                        ) => {
-                            // FIXME(effects): this should be removed
-                            // SPECIAL CASE FOR DESUGARED EFFECT PARAMS
-                            // This comes from the following example:
-                            //
-                            // ```
-                            // #[const_trait]
-                            // pub trait PartialEq<Rhs: ?Sized = Self> {}
-                            // impl const PartialEq for () {}
-                            // ```
-                            //
-                            // Since this is a const impl, we need to insert a host arg at the end of
-                            // `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
-                            // To work around this, we infer all arguments until we reach the host param.
-                            args.push(ctx.inferred_kind(&args, param, infer_args));
-                            params.next();
-                        }
                         (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
                         | (
                             GenericArg::Type(_) | GenericArg::Infer(_),
@@ -552,21 +526,34 @@ pub(crate) fn check_generic_arg_count(
                 synth_provided,
             }
         } else {
-            let num_missing_args = expected_max - provided;
+            // Check if associated type bounds are incorrectly written in impl block header like:
+            // ```
+            // trait Foo<T> {}
+            // impl Foo<T: Default> for u8 {}
+            // ```
+            let parent_is_impl_block = cx
+                .tcx()
+                .hir()
+                .parent_owner_iter(seg.hir_id)
+                .next()
+                .is_some_and(|(_, owner_node)| owner_node.is_impl_block());
+            if parent_is_impl_block {
+                let constraint_names: Vec<_> =
+                    gen_args.constraints.iter().map(|b| b.ident.name).collect();
+                let param_names: Vec<_> = gen_params
+                    .own_params
+                    .iter()
+                    .filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter
+                    .map(|param| param.name)
+                    .collect();
+                if constraint_names == param_names {
+                    // We set this to true and delay emitting `WrongNumberOfGenericArgs`
+                    // to provide a succinct error for cases like issue #113073
+                    all_params_are_binded = true;
+                };
+            }
 
-            let constraint_names: Vec<_> =
-                gen_args.constraints.iter().map(|b| b.ident.name).collect();
-            let param_names: Vec<_> = gen_params
-                .own_params
-                .iter()
-                .filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter
-                .map(|param| param.name)
-                .collect();
-            if constraint_names == param_names {
-                // We set this to true and delay emitting `WrongNumberOfGenericArgs`
-                // to provide a succinct error for cases like issue #113073
-                all_params_are_binded = true;
-            };
+            let num_missing_args = expected_max - provided;
 
             GenericArgsInfo::MissingTypesOrConsts {
                 num_missing_args,
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index e54f9486f6a..d6ff0cb9462 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1736,6 +1736,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ty::new_error(tcx, guar)
             };
 
+            // Check that the expected field type is WF. Otherwise, we emit no use-site error
+            // in the case of coercions for non-WF fields, which leads to incorrect error
+            // tainting. See issue #126272.
+            self.register_wf_obligation(
+                field_type.into(),
+                field.expr.span,
+                ObligationCauseCode::WellFormed(None),
+            );
+
             // Make sure to give a type to the field even if there's
             // an error, so we can continue type-checking.
             let ty = self.check_expr_with_hint(field.expr, field_type);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 40d9a2985da..841d25b54cc 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -48,28 +48,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Produces warning on the given node, if the current point in the
     /// function is unreachable, and there hasn't been another warning.
     pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) {
-        // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
-        // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
-        // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
-        if span.is_desugaring(DesugaringKind::CondTemporary) {
+        let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() else {
             return;
-        }
+        };
 
-        // Don't lint if the result of an async block or async function is `!`.
-        // This does not affect the unreachable lints *within* the body.
-        if span.is_desugaring(DesugaringKind::Async) {
-            return;
-        }
+        match span.desugaring_kind() {
+            // If span arose from a desugaring of `if` or `while`, then it is the condition
+            // itself, which diverges, that we are about to lint on. This gives suboptimal
+            // diagnostics. Instead, stop here so that the `if`- or `while`-expression's
+            // block is linted instead.
+            Some(DesugaringKind::CondTemporary) => return,
 
-        // Don't lint *within* the `.await` operator, since that's all just desugaring junk.
-        // We only want to lint if there is a subsequent expression after the `.await`.
-        if span.is_desugaring(DesugaringKind::Await) {
-            return;
-        }
+            // Don't lint if the result of an async block or async function is `!`.
+            // This does not affect the unreachable lints *within* the body.
+            Some(DesugaringKind::Async) => return,
 
-        let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() else {
-            return;
-        };
+            // Don't lint *within* the `.await` operator, since that's all just desugaring
+            // junk. We only want to lint if there is a subsequent expression after the
+            // `.await` operator.
+            Some(DesugaringKind::Await) => return,
+
+            _ => {}
+        }
 
         // Don't warn twice.
         self.diverges.set(Diverges::WarnedAlways);
@@ -404,8 +404,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         code: traits::ObligationCauseCode<'tcx>,
     ) {
         if !ty.references_error() {
-            let tail =
-                self.tcx.struct_tail_with_normalize(ty, |ty| self.normalize(span, ty), || {});
+            let tail = self.tcx.struct_tail_with_normalize(
+                ty,
+                |ty| {
+                    if self.next_trait_solver() {
+                        self.try_structurally_resolve_type(span, ty)
+                    } else {
+                        self.normalize(span, ty)
+                    }
+                },
+                || {},
+            );
             // Sized types have static alignment, and so do slices.
             if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) {
                 // Nothing else is required here.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index cef003e0a43..89e7227eda2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -22,7 +22,7 @@ use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
-use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
@@ -1140,8 +1140,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 .get(arg_idx + 1)
                                 .map(|&(_, sp)| sp)
                                 .unwrap_or_else(|| {
-                                    // Subtract one to move before `)`
-                                    call_expr.span.with_lo(call_expr.span.hi() - BytePos(1))
+                                    // Try to move before `)`. Note that `)` here is not necessarily
+                                    // the latin right paren, it could be a Unicode-confusable that
+                                    // looks like a `)`, so we must not use `- BytePos(1)`
+                                    // manipulations here.
+                                    self.tcx().sess.source_map().end_point(call_expr.span)
                                 });
 
                             // Include next comma
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index fa78b9ced12..758a1cefe63 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -265,11 +265,10 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
             Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. })
             | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => {
                 asm.operands.iter().find_map(|(op, _op_sp)| match op {
-                    hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
-                        // Inline assembly constants must be integers.
-                        Some(fcx.next_int_var())
-                    }
-                    hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
+                    hir::InlineAsmOperand::Const { anon_const }
+                    | hir::InlineAsmOperand::SymFn { anon_const }
+                        if anon_const.hir_id == id =>
+                    {
                         Some(fcx.next_ty_var(span))
                     }
                     _ => None,
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 82f732d69dc..28f537c87c4 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -774,18 +774,23 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         // instantiation that replaces `Self` with the object type itself. Hence,
         // a `&self` method will wind up with an argument type like `&dyn Trait`.
         let trait_ref = principal.with_self_ty(self.tcx, self_ty);
-        self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
-            this.push_candidate(
-                Candidate { item, kind: ObjectCandidate(new_trait_ref), import_ids: smallvec![] },
-                true,
-            );
-        });
+        self.assemble_candidates_for_bounds(
+            traits::supertraits(self.tcx, trait_ref),
+            |this, new_trait_ref, item| {
+                this.push_candidate(
+                    Candidate {
+                        item,
+                        kind: ObjectCandidate(new_trait_ref),
+                        import_ids: smallvec![],
+                    },
+                    true,
+                );
+            },
+        );
     }
 
     #[instrument(level = "debug", skip(self))]
     fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
-        // FIXME: do we want to commit to this behavior for param bounds?
-
         let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
             let bound_predicate = predicate.kind();
             match bound_predicate.skip_binder() {
@@ -806,7 +811,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             }
         });
 
-        self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
+        self.assemble_candidates_for_bounds(bounds, |this, poly_trait_ref, item| {
             this.push_candidate(
                 Candidate {
                     item,
@@ -820,15 +825,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
     // Do a search through a list of bounds, using a callback to actually
     // create the candidates.
-    fn elaborate_bounds<F>(
+    fn assemble_candidates_for_bounds<F>(
         &mut self,
         bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
         mut mk_cand: F,
     ) where
         F: for<'b> FnMut(&mut ProbeContext<'b, 'tcx>, ty::PolyTraitRef<'tcx>, ty::AssocItem),
     {
-        let tcx = self.tcx;
-        for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
+        for bound_trait_ref in bounds {
             debug!("elaborate_bounds(bound_trait_ref={:?})", bound_trait_ref);
             for item in self.impl_or_trait_item(bound_trait_ref.def_id()) {
                 if !self.has_applicable_self(&item) {
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index e64f4ebf45d..55f002291f0 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -219,7 +219,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // `async-await/async-closures/force-move-due-to-inferred-kind.rs`.
         //
         // 2. If the coroutine-closure is forced to be `FnOnce` due to the way it
-        // uses its upvars, but not *all* upvars would force the closure to `FnOnce`.
+        // uses its upvars (e.g. it consumes a non-copy value), but not *all* upvars
+        // would force the closure to `FnOnce`.
         // See the test: `async-await/async-closures/force-move-due-to-actually-fnonce.rs`.
         //
         // This would lead to an impossible to satisfy situation, since `AsyncFnOnce`
@@ -227,11 +228,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // we force the inner coroutine to also be `move`. This only matters for
         // coroutine-closures that are `move` since otherwise they themselves will
         // be borrowing from the outer environment, so there's no self-borrows occuring.
-        //
-        // One *important* note is that we do a call to `process_collected_capture_information`
-        // to eagerly test whether the coroutine would end up `FnOnce`, but we do this
-        // *before* capturing all the closure args by-value below, since that would always
-        // cause the analysis to return `FnOnce`.
         if let UpvarArgs::Coroutine(..) = args
             && let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) =
                 self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind")
@@ -246,19 +242,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 capture_clause = hir::CaptureBy::Value { move_kw };
             }
             // (2.) The way that the closure uses its upvars means it's `FnOnce`.
-            else if let (_, ty::ClosureKind::FnOnce, _) = self
-                .process_collected_capture_information(
-                    capture_clause,
-                    &delegate.capture_information,
-                )
-            {
+            else if self.coroutine_body_consumes_upvars(closure_def_id, body) {
                 capture_clause = hir::CaptureBy::Value { move_kw };
             }
         }
 
         // As noted in `lower_coroutine_body_with_moved_arguments`, we default the capture mode
         // to `ByRef` for the `async {}` block internal to async fns/closure. This means
-        // that we would *not* be moving all of the parameters into the async block by default.
+        // that we would *not* be moving all of the parameters into the async block in all cases.
+        // For example, when one of the arguments is `Copy`, we turn a consuming use into a copy of
+        // a reference, so for `async fn x(t: i32) {}`, we'd only take a reference to `t`.
         //
         // We force all of these arguments to be captured by move before we do expr use analysis.
         //
@@ -535,6 +528,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// Determines whether the body of the coroutine uses its upvars in a way that
+    /// consumes (i.e. moves) the value, which would force the coroutine to `FnOnce`.
+    /// In a more detailed comment above, we care whether this happens, since if
+    /// this happens, we want to force the coroutine to move all of the upvars it
+    /// would've borrowed from the parent coroutine-closure.
+    ///
+    /// This only really makes sense to be called on the child coroutine of a
+    /// coroutine-closure.
+    fn coroutine_body_consumes_upvars(
+        &self,
+        coroutine_def_id: LocalDefId,
+        body: &'tcx hir::Body<'tcx>,
+    ) -> bool {
+        // This block contains argument capturing details. Since arguments
+        // aren't upvars, we do not care about them for determining if the
+        // coroutine body actually consumes its upvars.
+        let hir::ExprKind::Block(&hir::Block { expr: Some(body), .. }, None) = body.value.kind
+        else {
+            bug!();
+        };
+        // Specifically, we only care about the *real* body of the coroutine.
+        // We skip out into the drop-temps within the block of the body in order
+        // to skip over the args of the desugaring.
+        let hir::ExprKind::DropTemps(body) = body.kind else {
+            bug!();
+        };
+
+        let mut delegate = InferBorrowKind {
+            closure_def_id: coroutine_def_id,
+            capture_information: Default::default(),
+            fake_reads: Default::default(),
+        };
+
+        let _ = euv::ExprUseVisitor::new(
+            &FnCtxt::new(self, self.tcx.param_env(coroutine_def_id), coroutine_def_id),
+            &mut delegate,
+        )
+        .consume_expr(body);
+
+        let (_, kind, _) = self.process_collected_capture_information(
+            hir::CaptureBy::Ref,
+            &delegate.capture_information,
+        );
+
+        matches!(kind, ty::ClosureKind::FnOnce)
+    }
+
     // Returns a list of `Ty`s for each upvar.
     fn final_upvar_tys(&self, closure_id: LocalDefId) -> Vec<Ty<'tcx>> {
         self.typeck_results
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 8c99b1f4447..96a6f52d60b 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -818,6 +818,19 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     });
     sess.time("layout_testing", || layout_test::test_layout(tcx));
     sess.time("abi_testing", || abi_test::test_abi(tcx));
+
+    // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
+    // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
+    // in MIR optimizations that may only be reachable through codegen, or other codepaths
+    // that requires the optimized/ctfe MIR, such as polymorphization, coroutine bodies,
+    // or evaluating consts.
+    if tcx.sess.opts.unstable_opts.validate_mir {
+        sess.time("ensuring_final_MIR_is_computable", || {
+            tcx.hir().par_body_owners(|def_id| {
+                tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
+            });
+        });
+    }
 }
 
 /// Runs the type-checking, region checking and other miscellaneous analysis
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index ce3b2f77f21..34f2dca7c42 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -315,7 +315,8 @@ fn test_search_paths_tracking_hash_different_order() {
     let early_dcx = EarlyDiagCtxt::new(JSON);
     const JSON: ErrorOutputType = ErrorOutputType::Json {
         pretty: false,
-        json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
+        json_rendered: HumanReadableErrorType::Default,
+        color_config: ColorConfig::Never,
     };
 
     let push = |opts: &mut Options, search_path| {
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7e4feb0a827..7a394a6d6c1 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -518,8 +518,8 @@ lint_non_binding_let_multi_suggestion =
 lint_non_binding_let_on_drop_type =
     non-binding let on a type that implements `Drop`
 
-lint_non_binding_let_on_sync_lock =
-    non-binding let on a synchronization lock
+lint_non_binding_let_on_sync_lock = non-binding let on a synchronization lock
+    .label = this lock is not assigned to a binding and is immediately dropped
 
 lint_non_binding_let_suggestion =
     consider binding to an unused variable to avoid immediately dropping the value
@@ -775,6 +775,10 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual
     .label = argument has type `{$arg_ty}`
     .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
 
+lint_unexpected_builtin_cfg = unexpected `--cfg {$cfg}` flag
+    .controlled_by = config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}`
+    .incoherent = manually setting a built-in cfg can and does create incoherent behaviors
+
 lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs`
 lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead
 lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index d8674817cb5..6b36944b208 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1924,14 +1924,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
 impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
         tcx: TyCtxt<'tcx>,
-        inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
+        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
         item: DefId,
         lifetime: DefId,
     ) -> Vec<ty::Region<'tcx>> {
         let item_generics = tcx.generics_of(item);
 
         inferred_outlives
-            .iter()
             .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
                     ty::ReEarlyParam(ebr)
@@ -1947,11 +1946,10 @@ impl ExplicitOutlivesRequirements {
     }
 
     fn lifetimes_outliving_type<'tcx>(
-        inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
+        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
         index: u32,
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
-            .iter()
             .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
                     a.is_param(index).then_some(b)
@@ -2094,7 +2092,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                 (
                                     Self::lifetimes_outliving_lifetime(
                                         cx.tcx,
-                                        inferred_outlives,
+                                        // don't warn if the inferred span actually came from the predicate we're looking at
+                                        // this happens if the type is recursively defined
+                                        inferred_outlives
+                                            .iter()
+                                            .filter(|(_, span)| !predicate.span.contains(*span)),
                                         item.owner_id.to_def_id(),
                                         region_def_id,
                                     ),
@@ -2116,7 +2118,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                     };
                                     let index = ty_generics.param_def_id_to_index[&def_id];
                                     (
-                                        Self::lifetimes_outliving_type(inferred_outlives, index),
+                                        Self::lifetimes_outliving_type(
+                                            // don't warn if the inferred span actually came from the predicate we're looking at
+                                            // this happens if the type is recursively defined
+                                            inferred_outlives.iter().filter(|(_, span)| {
+                                                !predicate.span.contains(*span)
+                                            }),
+                                            index,
+                                        ),
                                         &predicate.bounds,
                                         predicate.span,
                                         predicate.origin == PredicateOrigin::WhereClause,
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 11ad1aa0e8d..c9e2eee16b3 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -533,7 +533,7 @@ pub struct EarlyContext<'a> {
 }
 
 impl EarlyContext<'_> {
-    /// Emit a lint at the appropriate level, with an optional associated span and an existing
+    /// Emit a lint at the appropriate level, with an associated span and an existing
     /// diagnostic.
     ///
     /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
@@ -544,7 +544,21 @@ impl EarlyContext<'_> {
         span: MultiSpan,
         diagnostic: BuiltinLintDiag,
     ) {
-        self.opt_span_lint(lint, Some(span), |diag| {
+        self.opt_span_lint_with_diagnostics(lint, Some(span), diagnostic);
+    }
+
+    /// Emit a lint at the appropriate level, with an optional associated span and an existing
+    /// diagnostic.
+    ///
+    /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
+    #[rustc_lint_diagnostics]
+    pub fn opt_span_lint_with_diagnostics(
+        &self,
+        lint: &'static Lint,
+        span: Option<MultiSpan>,
+        diagnostic: BuiltinLintDiag,
+    ) {
+        self.opt_span_lint(lint, span, |diag| {
             diagnostics::decorate_lint(self.sess(), diagnostic, diag);
         });
     }
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index a96af076477..f289d4c81b3 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -438,5 +438,8 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
         BuiltinLintDiag::OutOfScopeMacroCalls { path } => {
             lints::OutOfScopeMacroCalls { path }.decorate_lint(diag)
         }
+        BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
+            lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
+        }
     }
 }
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 7b04e8c39e6..6fb0a624644 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -47,7 +47,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
     fn inlined_check_id(&mut self, id: ast::NodeId) {
         for early_lint in self.context.buffered.take(id) {
             let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
-            self.context.span_lint_with_diagnostics(lint_id.lint, span, diagnostic);
+            self.context.opt_span_lint_with_diagnostics(lint_id.lint, span, diagnostic);
         }
     }
 
diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs
index 92db8a88e42..1368cc87e3e 100644
--- a/compiler/rustc_lint/src/let_underscore.rs
+++ b/compiler/rustc_lint/src/let_underscore.rs
@@ -104,7 +104,6 @@ const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [
 ];
 
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) {
         if matches!(local.source, rustc_hir::LocalSource::AsyncFn) {
             return;
@@ -156,12 +155,12 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                 is_assign_desugar: matches!(local.source, rustc_hir::LocalSource::AssignDesugar(_)),
             };
             if is_sync_lock {
-                let mut span = MultiSpan::from_span(pat.span);
-                span.push_span_label(
-                    pat.span,
-                    "this lock is not assigned to a binding and is immediately dropped".to_string(),
+                let span = MultiSpan::from_span(pat.span);
+                cx.emit_span_lint(
+                    LET_UNDERSCORE_LOCK,
+                    span,
+                    NonBindingLet::SyncLock { sub, pat: pat.span },
                 );
-                cx.emit_span_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { sub });
             // Only emit let_underscore_drop for top-level `_` patterns.
             } else if can_use_init.is_some() {
                 cx.emit_span_lint(LET_UNDERSCORE_DROP, local.span, NonBindingLet::DropType { sub });
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 196b8fd52d5..4f3933d461b 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -543,7 +543,7 @@ fn register_builtins(store: &mut LintStore) {
     );
     store.register_removed(
         "suspicious_auto_trait_impls",
-        "no longer needed, see #93367 \
+        "no longer needed, see issue #93367 \
          <https://github.com/rust-lang/rust/issues/93367> for more information",
     );
     store.register_removed(
@@ -565,6 +565,11 @@ fn register_builtins(store: &mut LintStore) {
         "box_pointers",
         "it does not detect other kinds of allocations, and existed only for historical reasons",
     );
+    store.register_removed(
+        "byte_slice_in_packed_struct_with_derive",
+        "converted into hard error, see issue #107457 \
+         <https://github.com/rust-lang/rust/issues/107457> for more information",
+    )
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 46e7655a656..03962d796f4 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -957,6 +957,8 @@ pub struct BadOptAccessDiag<'a> {
 pub enum NonBindingLet {
     #[diag(lint_non_binding_let_on_sync_lock)]
     SyncLock {
+        #[label]
+        pat: Span,
         #[subdiagnostic]
         sub: NonBindingLetSub,
     },
@@ -2378,6 +2380,16 @@ pub mod unexpected_cfg_value {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_unexpected_builtin_cfg)]
+#[note(lint_controlled_by)]
+#[note(lint_incoherent)]
+pub struct UnexpectedBuiltinCfg {
+    pub(crate) cfg: String,
+    pub(crate) cfg_name: Symbol,
+    pub(crate) controlled_by: &'static str,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_macro_use_deprecated)]
 #[help]
 pub struct MacroUseDeprecated;
diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
index c39c86f6fe8..e3b1967da09 100644
--- a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
+++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
@@ -1,5 +1,5 @@
-//! Migration code for the `expr_fragment_specifier_2024`
-//! rule.
+//! Migration code for the `expr_fragment_specifier_2024` rule.
+
 use rustc_ast::token::{Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_session::lint::FutureIncompatibilityReason;
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index f3196cfed53..5b17c0d718a 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -458,8 +458,11 @@ fn lint_int_literal<'tcx>(
         }
 
         let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span };
-        let lit =
-            cx.sess().source_map().span_to_snippet(span).expect("must get snippet from literal");
+        let lit = cx
+            .sess()
+            .source_map()
+            .span_to_snippet(span)
+            .unwrap_or_else(|_| if negative { format!("-{v}") } else { v.to_string() });
         let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
             .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
 
@@ -485,6 +488,7 @@ fn lint_uint_literal<'tcx>(
         ast::LitKind::Int(v, _) => v.get(),
         _ => bug!(),
     };
+
     if lit_val < min || lit_val > max {
         if let Node::Expr(par_e) = cx.tcx.parent_hir_node(e.hir_id) {
             match par_e.kind {
@@ -526,7 +530,7 @@ fn lint_uint_literal<'tcx>(
                     .sess()
                     .source_map()
                     .span_to_snippet(lit.span)
-                    .expect("must get snippet from literal"),
+                    .unwrap_or_else(|_| lit_val.to_string()),
                 min,
                 max,
             },
@@ -551,14 +555,14 @@ fn lint_literal<'tcx>(
         }
         ty::Uint(t) => lint_uint_literal(cx, e, lit, t),
         ty::Float(t) => {
-            let is_infinite = match lit.node {
+            let (is_infinite, sym) = match lit.node {
                 ast::LitKind::Float(v, _) => match t {
                     // FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI
                     // issues resolved).
-                    ty::FloatTy::F16 => Ok(false),
-                    ty::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
-                    ty::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
-                    ty::FloatTy::F128 => Ok(false),
+                    ty::FloatTy::F16 => (Ok(false), v),
+                    ty::FloatTy::F32 => (v.as_str().parse().map(f32::is_infinite), v),
+                    ty::FloatTy::F64 => (v.as_str().parse().map(f64::is_infinite), v),
+                    ty::FloatTy::F128 => (Ok(false), v),
                 },
                 _ => bug!(),
             };
@@ -572,7 +576,7 @@ fn lint_literal<'tcx>(
                             .sess()
                             .source_map()
                             .span_to_snippet(lit.span)
-                            .expect("must get snippet from literal"),
+                            .unwrap_or_else(|_| sym.to_string()),
                     },
                 );
             }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 795333224ba..e2c05129ee2 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -675,6 +675,13 @@ trait UnusedDelimLint {
             return true;
         }
 
+        // Do not lint against parentheses around `&raw [const|mut] expr`.
+        // These parentheses will have to be added e.g. when calling a method on the result of this
+        // expression, and we want to avoid churn wrt adding and removing parentheses.
+        if matches!(inner.kind, ast::ExprKind::AddrOf(ast::BorrowKind::Raw, ..)) {
+            return true;
+        }
+
         // Check if LHS needs parens to prevent false-positives in cases like
         // `fn x() -> u8 { ({ 0 } + 1) }`.
         //
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 7172a47fb85..c731b03a875 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -26,7 +26,6 @@ declare_lint_pass! {
         BARE_TRAIT_OBJECTS,
         BINDINGS_WITH_VARIANT_NAME,
         BREAK_WITH_LABEL_AND_LOOP,
-        BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
         CENUM_IMPL_DROP_CAST,
         COHERENCE_LEAK_CHECK,
         CONFLICTING_REPR_HINTS,
@@ -43,6 +42,7 @@ declare_lint_pass! {
         DUPLICATE_MACRO_ATTRIBUTES,
         ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
         ELIDED_LIFETIMES_IN_PATHS,
+        EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
         EXPORTED_PRIVATE_DEPENDENCIES,
         FFI_UNWIND_CALLS,
         FORBIDDEN_LINT_GROUPS,
@@ -1267,7 +1267,7 @@ declare_lint! {
     Deny,
     "type parameter default erroneously allowed in invalid location",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
     };
 }
@@ -3290,6 +3290,39 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `explicit_builtin_cfgs_in_flags` lint detects builtin cfgs set via the `--cfg` flag.
+    ///
+    /// ### Example
+    ///
+    /// ```text
+    /// rustc --cfg unix
+    /// ```
+    ///
+    /// ```rust,ignore (needs command line option)
+    /// fn main() {}
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: unexpected `--cfg unix` flag
+    ///   |
+    ///   = note: config `unix` is only supposed to be controlled by `--target`
+    ///   = note: manually setting a built-in cfg can and does create incoherent behaviors
+    ///   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Setting builtin cfgs can and does produce incoherent behavior, it's better to the use
+    /// the appropriate `rustc` flag that controls the config. For example setting the `windows`
+    /// cfg but on Linux based target.
+    pub EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
+    Deny,
+    "detects builtin cfgs set via the `--cfg`"
+}
+
+declare_lint! {
     /// The `repr_transparent_external_private_fields` lint
     /// detects types marked `#[repr(transparent)]` that (transitively)
     /// contain an external ZST type marked `#[non_exhaustive]` or containing
@@ -4316,39 +4349,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field
-    /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or
-    /// more built-in traits.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// #[repr(packed)]
-    /// #[derive(Hash)]
-    /// struct FlexZeroSlice {
-    ///     width: u8,
-    ///     data: [u8],
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// This was previously accepted but is being phased out, because fields in packed structs are
-    /// now required to implement `Copy` for `derive` to work. Byte slices and string slices are a
-    /// temporary exception because certain crates depended on them.
-    pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
-    Warn,
-    "`[u8]` or `str` used in a packed struct with `derive`",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
-        reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>",
-    };
-    report_in_external_macro
-}
-
-declare_lint! {
     /// The `invalid_macro_export_arguments` lint detects cases where `#[macro_export]` is being used with invalid arguments.
     ///
     /// ### Example
@@ -4934,7 +4934,6 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
-    /// #![feature(unsafe_extern_blocks)]
     /// #![warn(missing_unsafe_on_extern)]
     /// #![allow(dead_code)]
     ///
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 19efa36b40f..0f07de43e80 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -746,6 +746,11 @@ pub enum BuiltinLintDiag {
     OutOfScopeMacroCalls {
         path: String,
     },
+    UnexpectedBuiltinCfg {
+        cfg: String,
+        cfg_name: Symbol,
+        controlled_by: &'static str,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
@@ -753,7 +758,7 @@ pub enum BuiltinLintDiag {
 #[derive(Debug)]
 pub struct BufferedEarlyLint {
     /// The span of code that we are linting on.
-    pub span: MultiSpan,
+    pub span: Option<MultiSpan>,
 
     /// The `NodeId` of the AST node that generated the lint.
     pub node_id: NodeId,
@@ -791,7 +796,7 @@ impl LintBuffer {
         self.add_early_lint(BufferedEarlyLint {
             lint_id: LintId::of(lint),
             node_id,
-            span: span.into(),
+            span: Some(span.into()),
             diagnostic,
         });
     }
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 4c1f78e6bee..b2ff9efb41c 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -259,6 +259,7 @@ fn main() {
     cmd.args(&components);
 
     for lib in output(&mut cmd).split_whitespace() {
+        let mut is_static = false;
         let name = if let Some(stripped) = lib.strip_prefix("-l") {
             stripped
         } else if let Some(stripped) = lib.strip_prefix('-') {
@@ -266,8 +267,24 @@ fn main() {
         } else if Path::new(lib).exists() {
             // On MSVC llvm-config will print the full name to libraries, but
             // we're only interested in the name part
-            let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
-            name.trim_end_matches(".lib")
+            // On Unix when we get a static library llvm-config will print the
+            // full name and we *are* interested in the path, but we need to
+            // handle it separately. For example, when statically linking to
+            // libzstd llvm-config will output something like
+            //   -lrt -ldl -lm -lz /usr/local/lib/libzstd.a -lxml2
+            // and we transform the zstd part into
+            //   cargo:rustc-link-search-native=/usr/local/lib
+            //   cargo:rustc-link-lib=static=zstd
+            let path = Path::new(lib);
+            if lib.ends_with(".a") {
+                is_static = true;
+                println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
+                let name = path.file_stem().unwrap().to_str().unwrap();
+                name.trim_start_matches("lib")
+            } else {
+                let name = path.file_name().unwrap().to_str().unwrap();
+                name.trim_end_matches(".lib")
+            }
         } else if lib.ends_with(".lib") {
             // Some MSVC libraries just come up with `.lib` tacked on, so chop
             // that off
@@ -285,7 +302,13 @@ fn main() {
             continue;
         }
 
-        let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" };
+        let kind = if name.starts_with("LLVM") {
+            llvm_kind
+        } else if is_static {
+            "static"
+        } else {
+            "dylib"
+        };
         println!("cargo:rustc-link-lib={kind}={name}");
     }
 
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 1705c016437..edab6b5ebde 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -747,18 +747,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option<DefId> {
-        if let Some(ret) = self.get_fn_output(def_id)
-            && let FnRetTy::Return(ty) = ret
-            && let TyKind::InferDelegation(sig_id, _) = ty.kind
-        {
-            return Some(sig_id);
-        }
-        None
-    }
-
-    #[inline]
-    pub fn delegation_sig_id(self, def_id: LocalDefId) -> DefId {
-        self.opt_delegation_sig_id(def_id).unwrap()
+        self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.opt_delegation_sig_id()
     }
 
     #[inline]
@@ -1176,17 +1165,23 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         }
         Node::ImplItem(ii) => {
             let kind = match ii.kind {
-                ImplItemKind::Const(..) => "assoc const",
-                ImplItemKind::Fn(..) => "method",
-                ImplItemKind::Type(_) => "assoc type",
+                ImplItemKind::Const(..) => "associated constant",
+                ImplItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
+                    ImplicitSelfKind::None => "associated function",
+                    _ => "method",
+                },
+                ImplItemKind::Type(_) => "associated type",
             };
             format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id))
         }
         Node::TraitItem(ti) => {
             let kind = match ti.kind {
-                TraitItemKind::Const(..) => "assoc constant",
-                TraitItemKind::Fn(..) => "trait method",
-                TraitItemKind::Type(..) => "assoc type",
+                TraitItemKind::Const(..) => "associated constant",
+                TraitItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
+                    ImplicitSelfKind::None => "associated function",
+                    _ => "trait method",
+                },
+                TraitItemKind::Type(..) => "associated type",
             };
 
             format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id))
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index b499604df87..5bd7736a3f3 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -28,6 +28,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::potential_query_instability)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(allocator_api)]
@@ -48,7 +49,6 @@
 #![feature(iter_from_coroutine)]
 #![feature(let_chains)]
 #![feature(macro_metavar_expr)]
-#![feature(min_exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(never_type)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 6a9e67f74da..8c27cac1ea8 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -228,9 +228,11 @@ pub fn explain_lint_level_source(
                 err.note_once(format!(
                     "`{flag} {hyphen_case_lint_name}` implied by `{flag} {hyphen_case_flag_val}`"
                 ));
-                err.help_once(format!(
-                    "to override `{flag} {hyphen_case_flag_val}` add `#[allow({name})]`"
-                ));
+                if matches!(orig_level, Level::Warn | Level::Deny) {
+                    err.help_once(format!(
+                        "to override `{flag} {hyphen_case_flag_val}` add `#[allow({name})]`"
+                    ));
+                }
             }
         }
         LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => {
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index ff6a3a9c12d..b7d290e58d2 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -28,7 +28,7 @@ pub struct CodegenFnAttrs {
     pub link_ordinal: Option<u16>,
     /// The `#[target_feature(enable = "...")]` attribute and the enabled
     /// features (only enabled features are supported right now).
-    pub target_features: Vec<Symbol>,
+    pub target_features: Vec<TargetFeature>,
     /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
     pub linkage: Option<Linkage>,
     /// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@@ -52,6 +52,15 @@ pub struct CodegenFnAttrs {
 }
 
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct TargetFeature {
+    /// The name of the target feature (e.g. "avx")
+    pub name: Symbol,
+    /// The feature is implied by another feature, rather than explicitly added by the
+    /// `#[target_feature]` attribute
+    pub implied: bool,
+}
+
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct PatchableFunctionEntry {
     /// Nops to prepend to the function
     prefix: u8,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c22c2e985ab..075eae02904 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -407,6 +407,10 @@ rustc_queries! {
         desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
     }
 
+    query impl_super_outlives(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
+        desc { |tcx| "elaborating supertrait outlives for trait of `{}`", tcx.def_path_str(key) }
+    }
+
     /// Look up all native libraries this crate depends on.
     /// These are assembled from the following places:
     /// - `extern` blocks (depending on their `link` attributes)
@@ -2183,6 +2187,12 @@ rustc_queries! {
         desc { "looking up supported target features" }
     }
 
+    query implied_target_features(feature: Symbol) -> &'tcx Vec<Symbol> {
+        arena_cache
+        eval_always
+        desc { "looking up implied target features" }
+    }
+
     query features_query(_: ()) -> &'tcx rustc_feature::Features {
         feedable
         desc { "looking up enabled feature gates" }
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 0ce5c613c4c..db56e0016a2 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -98,6 +98,15 @@ impl AssocItem {
         }
     }
 
+    pub fn descr(&self) -> &'static str {
+        match self.kind {
+            ty::AssocKind::Const => "const",
+            ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
+            ty::AssocKind::Fn => "associated function",
+            ty::AssocKind::Type => "type",
+        }
+    }
+
     pub fn is_impl_trait_in_trait(&self) -> bool {
         self.opt_rpitit_info.is_some()
     }
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 39c306a720f..8cb8e9af11c 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -376,7 +376,7 @@ pub struct GenericPredicates<'tcx> {
 
 impl<'tcx> GenericPredicates<'tcx> {
     pub fn instantiate(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         args: GenericArgsRef<'tcx>,
     ) -> InstantiatedPredicates<'tcx> {
@@ -386,20 +386,20 @@ impl<'tcx> GenericPredicates<'tcx> {
     }
 
     pub fn instantiate_own(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         args: GenericArgsRef<'tcx>,
     ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
         EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
     }
 
-    pub fn instantiate_own_identity(&self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
+    pub fn instantiate_own_identity(self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
         EarlyBinder::bind(self.predicates).iter_identity_copied()
     }
 
     #[instrument(level = "debug", skip(self, tcx))]
     fn instantiate_into(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         instantiated: &mut InstantiatedPredicates<'tcx>,
         args: GenericArgsRef<'tcx>,
@@ -413,14 +413,14 @@ impl<'tcx> GenericPredicates<'tcx> {
         instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp));
     }
 
-    pub fn instantiate_identity(&self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> {
+    pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> {
         let mut instantiated = InstantiatedPredicates::empty();
         self.instantiate_identity_into(tcx, &mut instantiated);
         instantiated
     }
 
     fn instantiate_identity_into(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         instantiated: &mut InstantiatedPredicates<'tcx>,
     ) {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index d7d27975f60..9204405d58f 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -869,7 +869,7 @@ where
                             metadata
                         }
                     } else {
-                        match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
+                        match tcx.struct_tail_for_codegen(pointee, cx.param_env()).kind() {
                             ty::Slice(_) | ty::Str => tcx.types.usize,
                             ty::Dynamic(data, _, ty::Dyn) => mk_dyn_vtable(data.principal()),
                             _ => bug!("TyAndLayout::field({:?}): not applicable", this),
@@ -1348,7 +1348,7 @@ impl<'tcx> TyCtxt<'tcx> {
             layout = layout.field(&cx, index);
             if !layout.is_sized() {
                 // If it is not sized, then the tail must still have at least a known static alignment.
-                let tail = self.struct_tail_erasing_lifetimes(layout.ty, param_env);
+                let tail = self.struct_tail_for_codegen(layout.ty, param_env);
                 if !matches!(tail.kind(), ty::Slice(..)) {
                     bug!(
                         "offset of not-statically-aligned field (type {:?}) cannot be computed statically",
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 3cf8531bb62..365f434a264 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -186,11 +186,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Should only be called if `ty` has no inference variables and does not
     /// need its lifetimes preserved (e.g. as part of codegen); otherwise
     /// normalization attempt may cause compiler bugs.
-    pub fn struct_tail_erasing_lifetimes(
-        self,
-        ty: Ty<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Ty<'tcx> {
+    pub fn struct_tail_for_codegen(self, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
         let tcx = self;
         tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {})
     }
@@ -203,7 +199,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity
     /// function to indicate no normalization should take place.
     ///
-    /// See also `struct_tail_erasing_lifetimes`, which is suitable for use
+    /// See also `struct_tail_for_codegen`, which is suitable for use
     /// during codegen.
     pub fn struct_tail_with_normalize(
         self,
@@ -272,13 +268,13 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Same as applying `struct_tail` on `source` and `target`, but only
     /// keeps going as long as the two types are instances of the same
     /// structure definitions.
-    /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
+    /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, dyn Trait)`,
     /// whereas struct_tail produces `T`, and `Trait`, respectively.
     ///
     /// Should only be called if the types have no inference variables and do
     /// not need their lifetimes preserved (e.g., as part of codegen); otherwise,
     /// normalization attempt may cause compiler bugs.
-    pub fn struct_lockstep_tails_erasing_lifetimes(
+    pub fn struct_lockstep_tails_for_codegen(
         self,
         source: Ty<'tcx>,
         target: Ty<'tcx>,
@@ -296,7 +292,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
     /// whereas struct_tail produces `T`, and `Trait`, respectively.
     ///
-    /// See also `struct_lockstep_tails_erasing_lifetimes`, which is suitable for use
+    /// See also `struct_lockstep_tails_for_codegen`, which is suitable for use
     /// during codegen.
     pub fn struct_lockstep_tails_with_normalize(
         self,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 3d4b706aa65..56896d945e5 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -75,6 +75,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             @call(mir_call, args) => {
                 self.parse_call(args)
             },
+            @call(mir_tail_call, args) => {
+                self.parse_tail_call(args)
+            },
             ExprKind::Match { scrutinee, arms, .. } => {
                 let discr = self.parse_operand(*scrutinee)?;
                 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
@@ -187,6 +190,25 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
         )
     }
 
+    fn parse_tail_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
+        parse_by_kind!(self, args[0], _, "tail call",
+            ExprKind::Call { fun, args, fn_span, .. } => {
+                let fun = self.parse_operand(*fun)?;
+                let args = args
+                    .iter()
+                    .map(|arg|
+                        Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span  } )
+                    )
+                    .collect::<PResult<Box<[_]>>>()?;
+                Ok(TerminatorKind::TailCall {
+                    func: fun,
+                    args,
+                    fn_span: *fn_span,
+                })
+            },
+        )
+    }
+
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
         parse_by_kind!(self, expr_id, expr, "rvalue",
             @call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 95fec154918..ab2bfcbca3a 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -208,14 +208,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 subpairs = cx.field_match_pairs(downcast_place, subpatterns);
 
                 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
-                    i == variant_index || {
-                        (cx.tcx.features().exhaustive_patterns
-                            || cx.tcx.features().min_exhaustive_patterns)
-                            && !v
-                                .inhabited_predicate(cx.tcx, adt_def)
-                                .instantiate(cx.tcx, args)
-                                .apply_ignore_module(cx.tcx, cx.param_env)
-                    }
+                    i == variant_index
+                        || !v
+                            .inhabited_predicate(cx.tcx, adt_def)
+                            .instantiate(cx.tcx, args)
+                            .apply_ignore_module(cx.tcx, cx.param_env)
                 }) && (adt_def.did().is_local()
                     || !adt_def.is_variant_list_non_exhaustive());
                 if irrefutable {
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 48018fcaa36..54a4204da71 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -5,6 +5,7 @@ use std::ops::Bound;
 use rustc_errors::DiagArgValue;
 use rustc_hir::def::DefKind;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
+use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::span_bug;
 use rustc_middle::thir::visit::Visitor;
@@ -31,7 +32,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
     safety_context: SafetyContext,
     /// The `#[target_feature]` attributes of the body. Used for checking
     /// calls to functions with `#[target_feature]` (RFC 2396).
-    body_target_features: &'tcx [Symbol],
+    body_target_features: &'tcx [TargetFeature],
     /// When inside the LHS of an assignment to a field, this is the type
     /// of the LHS and the span of the assignment expression.
     assignment_info: Option<Ty<'tcx>>,
@@ -442,14 +443,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     // is_like_wasm check in hir_analysis/src/collect.rs
                     let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
                     if !self.tcx.sess.target.options.is_like_wasm
-                        && !callee_features
-                            .iter()
-                            .all(|feature| self.body_target_features.contains(feature))
+                        && !callee_features.iter().all(|feature| {
+                            self.body_target_features.iter().any(|f| f.name == feature.name)
+                        })
                     {
                         let missing: Vec<_> = callee_features
                             .iter()
                             .copied()
-                            .filter(|feature| !self.body_target_features.contains(feature))
+                            .filter(|feature| {
+                                !feature.implied
+                                    && !self
+                                        .body_target_features
+                                        .iter()
+                                        .any(|body_feature| body_feature.name == feature.name)
+                            })
+                            .map(|feature| feature.name)
                             .collect();
                         let build_enabled = self
                             .tcx
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 64c6ff952c6..efaa75800fc 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -695,9 +695,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
 
         // Emit an extra note if the first uncovered witness would be uninhabited
         // if we disregard visibility.
-        let witness_1_is_privately_uninhabited = if (self.tcx.features().exhaustive_patterns
-            || self.tcx.features().min_exhaustive_patterns)
-            && let Some(witness_1) = witnesses.get(0)
+        let witness_1_is_privately_uninhabited = if let Some(witness_1) = witnesses.get(0)
             && let ty::Adt(adt, args) = witness_1.ty().kind()
             && adt.is_enum()
             && let Constructor::Variant(variant_index) = witness_1.ctor()
@@ -1059,7 +1057,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
                 err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary");
             } else if cx.is_foreign_non_exhaustive_enum(ty) {
                 err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
-            } else if cx.is_uninhabited(ty.inner()) && cx.tcx.features().min_exhaustive_patterns {
+            } else if cx.is_uninhabited(ty.inner()) {
                 // The type is uninhabited yet there is a witness: we must be in the `MaybeInvalid`
                 // case.
                 err.note(format!("`{ty}` is uninhabited but is not being matched by value, so a wildcard `_` is required"));
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index f864a13a31b..07ca51a67ae 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -25,6 +25,7 @@ rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index f30732e6aaf..324ddc5e799 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -479,7 +479,9 @@ impl<'tcx> Inliner<'tcx> {
             return Err("incompatible instruction set");
         }
 
-        if callee_attrs.target_features != self.codegen_fn_attrs.target_features {
+        let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name);
+        let this_feature_names = self.codegen_fn_attrs.target_features.iter().map(|f| f.name);
+        if callee_feature_names.ne(this_feature_names) {
             // In general it is not correct to inline a callee with target features that are a
             // subset of the caller. This is because the callee might contain calls, and the ABI of
             // those calls depends on the target features of the surrounding function. By moving a
@@ -503,6 +505,10 @@ impl<'tcx> Inliner<'tcx> {
     ) -> Result<(), &'static str> {
         let tcx = self.tcx;
 
+        if let Some(_) = callee_body.tainted_by_errors {
+            return Err("Body is tainted");
+        }
+
         let mut threshold = if self.caller_is_inline_forwarder {
             self.tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30)
         } else if cross_crate_inlinable {
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index df4f3ccb9b5..47758b56f8c 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -3,8 +3,10 @@ use std::iter;
 use rustc_index::IndexSlice;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
+use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
 use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
-use rustc_target::abi::Size;
+use rustc_target::abi::Integer;
+use rustc_type_ir::TyKind::*;
 
 use super::simplify::simplify_cfg;
 
@@ -42,10 +44,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                 should_cleanup = true;
                 continue;
             }
-            // unsound: https://github.com/rust-lang/rust/issues/124150
-            if tcx.sess.opts.unstable_opts.unsound_mir_opts
-                && SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some()
-            {
+            if SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() {
                 should_cleanup = true;
                 continue;
             }
@@ -264,33 +263,56 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
     }
 }
 
+/// Check if the cast constant using `IntToInt` is equal to the target constant.
+fn can_cast(
+    tcx: TyCtxt<'_>,
+    src_val: impl Into<u128>,
+    src_layout: TyAndLayout<'_>,
+    cast_ty: Ty<'_>,
+    target_scalar: ScalarInt,
+) -> bool {
+    let from_scalar = ScalarInt::try_from_uint(src_val.into(), src_layout.size).unwrap();
+    let v = match src_layout.ty.kind() {
+        Uint(_) => from_scalar.to_uint(src_layout.size),
+        Int(_) => from_scalar.to_int(src_layout.size) as u128,
+        _ => unreachable!("invalid int"),
+    };
+    let size = match *cast_ty.kind() {
+        Int(t) => Integer::from_int_ty(&tcx, t).size(),
+        Uint(t) => Integer::from_uint_ty(&tcx, t).size(),
+        _ => unreachable!("invalid int"),
+    };
+    let v = size.truncate(v);
+    let cast_scalar = ScalarInt::try_from_uint(v, size).unwrap();
+    cast_scalar == target_scalar
+}
+
 #[derive(Default)]
 struct SimplifyToExp {
-    transfrom_types: Vec<TransfromType>,
+    transfrom_kinds: Vec<TransfromKind>,
 }
 
 #[derive(Clone, Copy)]
-enum CompareType<'tcx, 'a> {
+enum ExpectedTransformKind<'tcx, 'a> {
     /// Identical statements.
     Same(&'a StatementKind<'tcx>),
     /// Assignment statements have the same value.
-    Eq(&'a Place<'tcx>, Ty<'tcx>, ScalarInt),
+    SameByEq { place: &'a Place<'tcx>, ty: Ty<'tcx>, scalar: ScalarInt },
     /// Enum variant comparison type.
-    Discr { place: &'a Place<'tcx>, ty: Ty<'tcx>, is_signed: bool },
+    Cast { place: &'a Place<'tcx>, ty: Ty<'tcx> },
 }
 
-enum TransfromType {
+enum TransfromKind {
     Same,
-    Eq,
-    Discr,
+    Cast,
 }
 
-impl From<CompareType<'_, '_>> for TransfromType {
-    fn from(compare_type: CompareType<'_, '_>) -> Self {
+impl From<ExpectedTransformKind<'_, '_>> for TransfromKind {
+    fn from(compare_type: ExpectedTransformKind<'_, '_>) -> Self {
         match compare_type {
-            CompareType::Same(_) => TransfromType::Same,
-            CompareType::Eq(_, _, _) => TransfromType::Eq,
-            CompareType::Discr { .. } => TransfromType::Discr,
+            ExpectedTransformKind::Same(_) => TransfromKind::Same,
+            ExpectedTransformKind::SameByEq { .. } => TransfromKind::Same,
+            ExpectedTransformKind::Cast { .. } => TransfromKind::Cast,
         }
     }
 }
@@ -354,7 +376,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
             return None;
         }
         let mut target_iter = targets.iter();
-        let (first_val, first_target) = target_iter.next().unwrap();
+        let (first_case_val, first_target) = target_iter.next().unwrap();
         let first_terminator_kind = &bbs[first_target].terminator().kind;
         // Check that destinations are identical, and if not, then don't optimize this block
         if !targets
@@ -364,24 +386,20 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
             return None;
         }
 
-        let discr_size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size;
+        let discr_layout = tcx.layout_of(param_env.and(discr_ty)).unwrap();
         let first_stmts = &bbs[first_target].statements;
-        let (second_val, second_target) = target_iter.next().unwrap();
+        let (second_case_val, second_target) = target_iter.next().unwrap();
         let second_stmts = &bbs[second_target].statements;
         if first_stmts.len() != second_stmts.len() {
             return None;
         }
 
-        fn int_equal(l: ScalarInt, r: impl Into<u128>, size: Size) -> bool {
-            l.to_bits_unchecked() == ScalarInt::try_from_uint(r, size).unwrap().to_bits_unchecked()
-        }
-
         // We first compare the two branches, and then the other branches need to fulfill the same conditions.
-        let mut compare_types = Vec::new();
+        let mut expected_transform_kinds = Vec::new();
         for (f, s) in iter::zip(first_stmts, second_stmts) {
             let compare_type = match (&f.kind, &s.kind) {
                 // If two statements are exactly the same, we can optimize.
-                (f_s, s_s) if f_s == s_s => CompareType::Same(f_s),
+                (f_s, s_s) if f_s == s_s => ExpectedTransformKind::Same(f_s),
 
                 // If two statements are assignments with the match values to the same place, we can optimize.
                 (
@@ -395,22 +413,29 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
                         f_c.const_.try_eval_scalar_int(tcx, param_env),
                         s_c.const_.try_eval_scalar_int(tcx, param_env),
                     ) {
-                        (Some(f), Some(s)) if f == s => CompareType::Eq(lhs_f, f_c.const_.ty(), f),
-                        // Enum variants can also be simplified to an assignment statement if their values are equal.
-                        // We need to consider both unsigned and signed scenarios here.
+                        (Some(f), Some(s)) if f == s => ExpectedTransformKind::SameByEq {
+                            place: lhs_f,
+                            ty: f_c.const_.ty(),
+                            scalar: f,
+                        },
+                        // Enum variants can also be simplified to an assignment statement,
+                        // if we can use `IntToInt` cast to get an equal value.
                         (Some(f), Some(s))
-                            if ((f_c.const_.ty().is_signed() || discr_ty.is_signed())
-                                && int_equal(f, first_val, discr_size)
-                                && int_equal(s, second_val, discr_size))
-                                || (Some(f) == ScalarInt::try_from_uint(first_val, f.size())
-                                    && Some(s)
-                                        == ScalarInt::try_from_uint(second_val, s.size())) =>
+                            if (can_cast(
+                                tcx,
+                                first_case_val,
+                                discr_layout,
+                                f_c.const_.ty(),
+                                f,
+                            ) && can_cast(
+                                tcx,
+                                second_case_val,
+                                discr_layout,
+                                f_c.const_.ty(),
+                                s,
+                            )) =>
                         {
-                            CompareType::Discr {
-                                place: lhs_f,
-                                ty: f_c.const_.ty(),
-                                is_signed: f_c.const_.ty().is_signed() || discr_ty.is_signed(),
-                            }
+                            ExpectedTransformKind::Cast { place: lhs_f, ty: f_c.const_.ty() }
                         }
                         _ => {
                             return None;
@@ -421,47 +446,36 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
                 // Otherwise we cannot optimize. Try another block.
                 _ => return None,
             };
-            compare_types.push(compare_type);
+            expected_transform_kinds.push(compare_type);
         }
 
         // All remaining BBs need to fulfill the same pattern as the two BBs from the previous step.
         for (other_val, other_target) in target_iter {
             let other_stmts = &bbs[other_target].statements;
-            if compare_types.len() != other_stmts.len() {
+            if expected_transform_kinds.len() != other_stmts.len() {
                 return None;
             }
-            for (f, s) in iter::zip(&compare_types, other_stmts) {
+            for (f, s) in iter::zip(&expected_transform_kinds, other_stmts) {
                 match (*f, &s.kind) {
-                    (CompareType::Same(f_s), s_s) if f_s == s_s => {}
+                    (ExpectedTransformKind::Same(f_s), s_s) if f_s == s_s => {}
                     (
-                        CompareType::Eq(lhs_f, f_ty, val),
+                        ExpectedTransformKind::SameByEq { place: lhs_f, ty: f_ty, scalar },
                         StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
                     ) if lhs_f == lhs_s
                         && s_c.const_.ty() == f_ty
-                        && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(val) => {}
+                        && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(scalar) => {}
                     (
-                        CompareType::Discr { place: lhs_f, ty: f_ty, is_signed },
+                        ExpectedTransformKind::Cast { place: lhs_f, ty: f_ty },
                         StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
-                    ) if lhs_f == lhs_s && s_c.const_.ty() == f_ty => {
-                        let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env) else {
-                            return None;
-                        };
-                        if is_signed
-                            && s_c.const_.ty().is_signed()
-                            && int_equal(f, other_val, discr_size)
-                        {
-                            continue;
-                        }
-                        if Some(f) == ScalarInt::try_from_uint(other_val, f.size()) {
-                            continue;
-                        }
-                        return None;
-                    }
+                    ) if let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env)
+                        && lhs_f == lhs_s
+                        && s_c.const_.ty() == f_ty
+                        && can_cast(tcx, other_val, discr_layout, f_ty, f) => {}
                     _ => return None,
                 }
             }
         }
-        self.transfrom_types = compare_types.into_iter().map(|c| c.into()).collect();
+        self.transfrom_kinds = expected_transform_kinds.into_iter().map(|c| c.into()).collect();
         Some(())
     }
 
@@ -479,13 +493,13 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
         let (_, first) = targets.iter().next().unwrap();
         let first = &bbs[first];
 
-        for (t, s) in iter::zip(&self.transfrom_types, &first.statements) {
+        for (t, s) in iter::zip(&self.transfrom_kinds, &first.statements) {
             match (t, &s.kind) {
-                (TransfromType::Same, _) | (TransfromType::Eq, _) => {
+                (TransfromKind::Same, _) => {
                     patch.add_statement(parent_end, s.kind.clone());
                 }
                 (
-                    TransfromType::Discr,
+                    TransfromKind::Cast,
                     StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
                 ) => {
                     let operand = Operand::Copy(Place::from(discr_local));
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index df2abf6dc9c..0ae635f9b73 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1019,7 +1019,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
             if ty.is_sized(tcx.tcx, param_env) {
                 return false;
             }
-            let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env);
+            let tail = tcx.struct_tail_for_codegen(ty, param_env);
             match tail.kind() {
                 ty::Foreign(..) => false,
                 ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
@@ -1029,7 +1029,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
         if type_has_metadata(inner_source) {
             (inner_source, inner_target)
         } else {
-            tcx.struct_lockstep_tails_erasing_lifetimes(inner_source, inner_target, param_env)
+            tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, param_env)
         }
     };
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 60beaa0df84..00837f7cdd8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -7,7 +7,7 @@ use rustc_type_ir::data_structures::HashMap;
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
-use rustc_type_ir::{self as ty, Interner, Upcast as _};
+use rustc_type_ir::{self as ty, elaborate, Interner, Upcast as _};
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 use tracing::instrument;
 
@@ -458,28 +458,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
             ))
         }
 
-        ty::FnDef(..) | ty::FnPtr(..) => {
-            let bound_sig = self_ty.fn_sig(cx);
-            let sig = bound_sig.skip_binder();
-            let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future);
-            // `FnDef` and `FnPtr` only implement `AsyncFn*` when their
-            // return type implements `Future`.
-            let nested = vec![
-                bound_sig
-                    .rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()]))
-                    .upcast(cx),
-            ];
-            let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput);
-            let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]);
-            Ok((
-                bound_sig.rebind(AsyncCallableRelevantTypes {
-                    tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()),
-                    output_coroutine_ty: sig.output(),
-                    coroutine_return_ty: future_output_ty,
-                }),
-                nested,
-            ))
+        ty::FnDef(def_id, _) => {
+            let sig = self_ty.fn_sig(cx);
+            if sig.skip_binder().is_fn_trait_compatible() && !cx.has_target_features(def_id) {
+                fn_item_to_async_callable(cx, sig)
+            } else {
+                Err(NoSolution)
+            }
+        }
+        ty::FnPtr(..) => {
+            let sig = self_ty.fn_sig(cx);
+            if sig.skip_binder().is_fn_trait_compatible() {
+                fn_item_to_async_callable(cx, sig)
+            } else {
+                Err(NoSolution)
+            }
         }
+
         ty::Closure(_, args) => {
             let args = args.as_closure();
             let bound_sig = args.sig();
@@ -563,6 +558,29 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
     }
 }
 
+fn fn_item_to_async_callable<I: Interner>(
+    cx: I,
+    bound_sig: ty::Binder<I, ty::FnSig<I>>,
+) -> Result<(ty::Binder<I, AsyncCallableRelevantTypes<I>>, Vec<I::Predicate>), NoSolution> {
+    let sig = bound_sig.skip_binder();
+    let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future);
+    // `FnDef` and `FnPtr` only implement `AsyncFn*` when their
+    // return type implements `Future`.
+    let nested = vec![
+        bound_sig.rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()])).upcast(cx),
+    ];
+    let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput);
+    let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]);
+    Ok((
+        bound_sig.rebind(AsyncCallableRelevantTypes {
+            tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()),
+            output_coroutine_ty: sig.output(),
+            coroutine_return_ty: future_output_ty,
+        }),
+        nested,
+    ))
+}
+
 /// Given a coroutine-closure, project to its returned coroutine when we are *certain*
 /// that the closure's kind is compatible with the goal.
 fn coroutine_closure_to_certain_coroutine<I: Interner>(
@@ -671,11 +689,19 @@ where
 {
     let cx = ecx.cx();
     let mut requirements = vec![];
-    requirements.extend(
+    // Elaborating all supertrait outlives obligations here is not soundness critical,
+    // since if we just used the unelaborated set, then the transitive supertraits would
+    // be reachable when proving the former. However, since we elaborate all supertrait
+    // outlives obligations when confirming impls, we would end up with a different set
+    // of outlives obligations here if we didn't do the same, leading to ambiguity.
+    // FIXME(-Znext-solver=coinductive): Adding supertraits here can be removed once we
+    // make impls coinductive always, since they'll always need to prove their supertraits.
+    requirements.extend(elaborate::elaborate(
+        cx,
         cx.explicit_super_predicates_of(trait_ref.def_id)
             .iter_instantiated(cx, trait_ref.args)
             .map(|(pred, _)| pred),
-    );
+    ));
 
     // FIXME(associated_const_equality): Also add associated consts to
     // the requirements here.
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 4474bbc2351..b1dba712f79 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -87,6 +87,19 @@ where
                 .map(|pred| goal.with(cx, pred));
             ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
 
+            // We currently elaborate all supertrait outlives obligations from impls.
+            // This can be removed when we actually do coinduction correctly, and prove
+            // all supertrait obligations unconditionally.
+            let goal_clause: I::Clause = goal.predicate.upcast(cx);
+            for clause in elaborate::elaborate(cx, [goal_clause]) {
+                if matches!(
+                    clause.kind().skip_binder(),
+                    ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
+                ) {
+                    ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
+                }
+            }
+
             ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
         })
     }
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index f34ef071e21..8fdfbcee385 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -8,7 +8,7 @@ use rustc_span::{sym, BytePos, Span};
 use thin_vec::ThinVec;
 use tracing::debug;
 
-use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
+use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle};
 use crate::{errors, fluent_generated as fluent, maybe_whole};
 
 // Public for rustfmt usage
@@ -313,8 +313,8 @@ impl<'a> Parser<'a> {
                 // inner attribute, for possible later processing in a `LazyAttrTokenStream`.
                 if let Capturing::Yes = self.capture_state.capturing {
                     let end_pos = self.num_bump_calls;
-                    let range = start_pos..end_pos;
-                    self.capture_state.inner_attr_ranges.insert(attr.id, range);
+                    let parser_range = ParserRange(start_pos..end_pos);
+                    self.capture_state.inner_attr_parser_ranges.insert(attr.id, parser_range);
                 }
                 attrs.push(attr);
             } else {
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 611dbc0535c..abf61036c2d 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -10,7 +10,10 @@ use rustc_errors::PResult;
 use rustc_session::parse::ParseSess;
 use rustc_span::{sym, Span, DUMMY_SP};
 
-use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor};
+use super::{
+    Capturing, FlatToken, ForceCollect, NodeRange, NodeReplacement, Parser, ParserRange,
+    TokenCursor,
+};
 
 /// A wrapper type to ensure that the parser handles outer attributes correctly.
 /// When we parse outer attributes, we need to ensure that we capture tokens
@@ -28,8 +31,8 @@ use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCurso
 #[derive(Debug, Clone)]
 pub struct AttrWrapper {
     attrs: AttrVec,
-    // The start of the outer attributes in the token cursor.
-    // This allows us to create a `ReplaceRange` for the entire attribute
+    // The start of the outer attributes in the parser's token stream.
+    // This lets us create a `NodeReplacement` for the entire attribute
     // target, including outer attributes.
     start_pos: u32,
 }
@@ -53,10 +56,9 @@ impl AttrWrapper {
 
     /// Prepend `self.attrs` to `attrs`.
     // FIXME: require passing an NT to prevent misuse of this method
-    pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) {
-        let mut self_attrs = self.attrs;
-        mem::swap(attrs, &mut self_attrs);
-        attrs.extend(self_attrs);
+    pub(crate) fn prepend_to_nt_inner(mut self, attrs: &mut AttrVec) {
+        mem::swap(attrs, &mut self.attrs);
+        attrs.extend(self.attrs);
     }
 
     pub fn is_empty(&self) -> bool {
@@ -89,7 +91,7 @@ struct LazyAttrTokenStreamImpl {
     cursor_snapshot: TokenCursor,
     num_calls: u32,
     break_last_token: bool,
-    replace_ranges: Box<[ReplaceRange]>,
+    node_replacements: Box<[NodeReplacement]>,
 }
 
 impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
@@ -104,21 +106,24 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
             .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next())))
             .take(self.num_calls as usize);
 
-        if self.replace_ranges.is_empty() {
+        if self.node_replacements.is_empty() {
             make_attr_token_stream(tokens, self.break_last_token)
         } else {
             let mut tokens: Vec<_> = tokens.collect();
-            let mut replace_ranges = self.replace_ranges.to_vec();
-            replace_ranges.sort_by_key(|(range, _)| range.start);
+            let mut node_replacements = self.node_replacements.to_vec();
+            node_replacements.sort_by_key(|(range, _)| range.0.start);
 
             #[cfg(debug_assertions)]
-            for [(range, tokens), (next_range, next_tokens)] in replace_ranges.array_windows() {
+            for [(node_range, tokens), (next_node_range, next_tokens)] in
+                node_replacements.array_windows()
+            {
                 assert!(
-                    range.end <= next_range.start || range.end >= next_range.end,
-                    "Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})",
-                    range,
+                    node_range.0.end <= next_node_range.0.start
+                        || node_range.0.end >= next_node_range.0.end,
+                    "Node ranges should be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})",
+                    node_range,
                     tokens,
-                    next_range,
+                    next_node_range,
                     next_tokens,
                 );
             }
@@ -136,20 +141,23 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
             // start position, we ensure that any (outer) replace range which
             // encloses another (inner) replace range will fully overwrite the
             // inner range's replacement.
-            for (range, target) in replace_ranges.into_iter().rev() {
-                assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}");
+            for (node_range, target) in node_replacements.into_iter().rev() {
+                assert!(
+                    !node_range.0.is_empty(),
+                    "Cannot replace an empty node range: {:?}",
+                    node_range.0
+                );
 
                 // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, plus
                 // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the
                 // total length of `tokens` constant throughout the replacement process, allowing
-                // us to use all of the `ReplaceRanges` entries without adjusting indices.
+                // us to do all replacements without adjusting indices.
                 let target_len = target.is_some() as usize;
                 tokens.splice(
-                    (range.start as usize)..(range.end as usize),
-                    target
-                        .into_iter()
-                        .map(|target| FlatToken::AttrsTarget(target))
-                        .chain(iter::repeat(FlatToken::Empty).take(range.len() - target_len)),
+                    (node_range.0.start as usize)..(node_range.0.end as usize),
+                    target.into_iter().map(|target| FlatToken::AttrsTarget(target)).chain(
+                        iter::repeat(FlatToken::Empty).take(node_range.0.len() - target_len),
+                    ),
                 );
             }
             make_attr_token_stream(tokens.into_iter(), self.break_last_token)
@@ -216,7 +224,7 @@ impl<'a> Parser<'a> {
         let cursor_snapshot = self.token_cursor.clone();
         let start_pos = self.num_bump_calls;
         let has_outer_attrs = !attrs.attrs.is_empty();
-        let replace_ranges_start = self.capture_state.replace_ranges.len();
+        let parser_replacements_start = self.capture_state.parser_replacements.len();
 
         // We set and restore `Capturing::Yes` on either side of the call to
         // `f`, so we can distinguish the outermost call to
@@ -271,7 +279,7 @@ impl<'a> Parser<'a> {
             return Ok(ret);
         }
 
-        let replace_ranges_end = self.capture_state.replace_ranges.len();
+        let parser_replacements_end = self.capture_state.parser_replacements.len();
 
         assert!(
             !(self.break_last_token && capture_trailing),
@@ -288,15 +296,16 @@ impl<'a> Parser<'a> {
 
         let num_calls = end_pos - start_pos;
 
-        // Take the captured ranges for any inner attributes that we parsed in
-        // `Parser::parse_inner_attributes`, and pair them in a `ReplaceRange`
-        // with `None`, which means the relevant tokens will be removed. (More
-        // details below.)
-        let mut inner_attr_replace_ranges = Vec::new();
+        // Take the captured `ParserRange`s for any inner attributes that we parsed in
+        // `Parser::parse_inner_attributes`, and pair them in a `ParserReplacement` with `None`,
+        // which means the relevant tokens will be removed. (More details below.)
+        let mut inner_attr_parser_replacements = Vec::new();
         for attr in ret.attrs() {
             if attr.style == ast::AttrStyle::Inner {
-                if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&attr.id) {
-                    inner_attr_replace_ranges.push((attr_range, None));
+                if let Some(inner_attr_parser_range) =
+                    self.capture_state.inner_attr_parser_ranges.remove(&attr.id)
+                {
+                    inner_attr_parser_replacements.push((inner_attr_parser_range, None));
                 } else {
                     self.dcx().span_delayed_bug(attr.span, "Missing token range for attribute");
                 }
@@ -305,37 +314,41 @@ impl<'a> Parser<'a> {
 
         // This is hot enough for `deep-vector` that checking the conditions for an empty iterator
         // is measurably faster than actually executing the iterator.
-        let replace_ranges: Box<[ReplaceRange]> =
-            if replace_ranges_start == replace_ranges_end && inner_attr_replace_ranges.is_empty() {
-                Box::new([])
-            } else {
-                // Grab any replace ranges that occur *inside* the current AST node. We will
-                // perform the actual replacement only when we convert the `LazyAttrTokenStream` to
-                // an `AttrTokenStream`.
-                self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
-                    .iter()
-                    .cloned()
-                    .chain(inner_attr_replace_ranges.iter().cloned())
-                    .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data))
-                    .collect()
-            };
+        let node_replacements: Box<[_]> = if parser_replacements_start == parser_replacements_end
+            && inner_attr_parser_replacements.is_empty()
+        {
+            Box::new([])
+        } else {
+            // Grab any replace ranges that occur *inside* the current AST node. Convert them
+            // from `ParserRange` form to `NodeRange` form. We will perform the actual
+            // replacement only when we convert the `LazyAttrTokenStream` to an
+            // `AttrTokenStream`.
+            self.capture_state.parser_replacements
+                [parser_replacements_start..parser_replacements_end]
+                .iter()
+                .cloned()
+                .chain(inner_attr_parser_replacements.iter().cloned())
+                .map(|(parser_range, data)| (NodeRange::new(parser_range, start_pos), data))
+                .collect()
+        };
 
         // What is the status here when parsing the example code at the top of this method?
         //
         // When parsing `g`:
         // - `start_pos..end_pos` is `12..33` (`fn g { ... }`, excluding the outer attr).
-        // - `inner_attr_replace_ranges` has one entry (`5..15`, when counting from `fn`), to
+        // - `inner_attr_parser_replacements` has one entry (`ParserRange(17..27)`), to
         //   delete the inner attr's tokens.
-        //   - This entry is put into the lazy tokens for `g`, i.e. deleting the inner attr from
-        //     those tokens (if they get evaluated).
+        //   - This entry is converted to `NodeRange(5..15)` (relative to the `fn`) and put into
+        //     the lazy tokens for `g`, i.e. deleting the inner attr from those tokens (if they get
+        //     evaluated).
         //   - Those lazy tokens are also put into an `AttrsTarget` that is appended to `self`'s
         //     replace ranges at the bottom of this function, for processing when parsing `m`.
-        // - `replace_ranges_start..replace_ranges_end` is empty.
+        // - `parser_replacements_start..parser_replacements_end` is empty.
         //
         // When parsing `m`:
         // - `start_pos..end_pos` is `0..34` (`mod m`, excluding the `#[cfg_eval]` attribute).
-        // - `inner_attr_replace_ranges` is empty.
-        // - `replace_range_start..replace_ranges_end` has one entry.
+        // - `inner_attr_parser_replacements` is empty.
+        // - `parser_replacements_start..parser_replacements_end` has one entry.
         //   - One `AttrsTarget` (added below when parsing `g`) to replace all of `g` (`3..33`,
         //     including its outer attribute), with:
         //     - `attrs`: includes the outer and the inner attr.
@@ -346,7 +359,7 @@ impl<'a> Parser<'a> {
             num_calls,
             cursor_snapshot,
             break_last_token: self.break_last_token,
-            replace_ranges,
+            node_replacements,
         });
 
         // If we support tokens and don't already have them, store the newly captured tokens.
@@ -367,7 +380,7 @@ impl<'a> Parser<'a> {
             // What is the status here when parsing the example code at the top of this method?
             //
             // When parsing `g`, we add one entry:
-            // - The `start_pos..end_pos` (`3..33`) entry has a new `AttrsTarget` with:
+            // - The pushed entry (`ParserRange(3..33)`) has a new `AttrsTarget` with:
             //   - `attrs`: includes the outer and the inner attr.
             //   - `tokens`: lazy tokens for `g` (with its inner attr deleted).
             //
@@ -378,12 +391,14 @@ impl<'a> Parser<'a> {
             // cfg-expand this AST node.
             let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos };
             let target = AttrsTarget { attrs: ret.attrs().iter().cloned().collect(), tokens };
-            self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target)));
+            self.capture_state
+                .parser_replacements
+                .push((ParserRange(start_pos..end_pos), Some(target)));
         } else if matches!(self.capture_state.capturing, Capturing::No) {
             // Only clear the ranges once we've finished capturing entirely, i.e. we've finished
             // the outermost call to this method.
-            self.capture_state.replace_ranges.clear();
-            self.capture_state.inner_attr_ranges.clear();
+            self.capture_state.parser_replacements.clear();
+            self.capture_state.inner_attr_parser_ranges.clear();
         }
         Ok(ret)
     }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 1b053c39e64..ccf8dcdf0b6 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -41,14 +41,6 @@ use super::{
 use crate::{errors, maybe_recover_from_interpolated_ty_qpath};
 
 #[derive(Debug)]
-pub(super) enum LhsExpr {
-    // Already parsed just the outer attributes.
-    Unparsed { attrs: AttrWrapper },
-    // Already parsed the expression.
-    Parsed { expr: P<Expr>, starts_statement: bool },
-}
-
-#[derive(Debug)]
 enum DestructuredFloat {
     /// 1e2
     Single(Symbol, Span),
@@ -113,30 +105,31 @@ impl<'a> Parser<'a> {
         r: Restrictions,
         attrs: AttrWrapper,
     ) -> PResult<'a, P<Expr>> {
-        self.with_res(r, |this| this.parse_expr_assoc_with(0, LhsExpr::Unparsed { attrs }))
+        self.with_res(r, |this| this.parse_expr_assoc_with(0, attrs))
     }
 
     /// Parses an associative expression with operators of at least `min_prec` precedence.
     pub(super) fn parse_expr_assoc_with(
         &mut self,
         min_prec: usize,
-        lhs: LhsExpr,
+        attrs: AttrWrapper,
     ) -> PResult<'a, P<Expr>> {
-        let mut starts_stmt = false;
-        let mut lhs = match lhs {
-            LhsExpr::Parsed { expr, starts_statement } => {
-                starts_stmt = starts_statement;
-                expr
-            }
-            LhsExpr::Unparsed { attrs } => {
-                if self.token.is_range_separator() {
-                    return self.parse_expr_prefix_range(attrs);
-                } else {
-                    self.parse_expr_prefix(attrs)?
-                }
-            }
+        let lhs = if self.token.is_range_separator() {
+            return self.parse_expr_prefix_range(attrs);
+        } else {
+            self.parse_expr_prefix(attrs)?
         };
+        self.parse_expr_assoc_rest_with(min_prec, false, lhs)
+    }
 
+    /// Parses the rest of an associative expression (i.e. the part after the lhs) with operators
+    /// of at least `min_prec` precedence.
+    pub(super) fn parse_expr_assoc_rest_with(
+        &mut self,
+        min_prec: usize,
+        starts_stmt: bool,
+        mut lhs: P<Expr>,
+    ) -> PResult<'a, P<Expr>> {
         if !self.should_continue_as_assoc_expr(&lhs) {
             return Ok(lhs);
         }
@@ -272,7 +265,7 @@ impl<'a> Parser<'a> {
             };
             let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
                 let attrs = this.parse_outer_attributes()?;
-                this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::Unparsed { attrs })
+                this.parse_expr_assoc_with(prec + prec_adjustment, attrs)
             })?;
 
             let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
@@ -447,7 +440,7 @@ impl<'a> Parser<'a> {
             let maybe_lt = self.token.clone();
             let attrs = self.parse_outer_attributes()?;
             Some(
-                self.parse_expr_assoc_with(prec + 1, LhsExpr::Unparsed { attrs })
+                self.parse_expr_assoc_with(prec + 1, attrs)
                     .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,
             )
         } else {
@@ -504,12 +497,9 @@ impl<'a> Parser<'a> {
             let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
                 // RHS must be parsed with more associativity than the dots.
                 let attrs = this.parse_outer_attributes()?;
-                this.parse_expr_assoc_with(
-                    op.unwrap().precedence() + 1,
-                    LhsExpr::Unparsed { attrs },
-                )
-                .map(|x| (lo.to(x.span), Some(x)))
-                .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
+                this.parse_expr_assoc_with(op.unwrap().precedence() + 1, attrs)
+                    .map(|x| (lo.to(x.span), Some(x)))
+                    .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
             } else {
                 (lo, None)
             };
@@ -889,7 +879,7 @@ impl<'a> Parser<'a> {
         mut e: P<Expr>,
         lo: Span,
     ) -> PResult<'a, P<Expr>> {
-        let res = ensure_sufficient_stack(|| {
+        let mut res = ensure_sufficient_stack(|| {
             loop {
                 let has_question =
                     if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
@@ -936,17 +926,13 @@ impl<'a> Parser<'a> {
 
         // Stitch the list of outer attributes onto the return value. A little
         // bit ugly, but the best way given the current code structure.
-        if attrs.is_empty() {
-            res
-        } else {
-            res.map(|expr| {
-                expr.map(|mut expr| {
-                    attrs.extend(expr.attrs);
-                    expr.attrs = attrs;
-                    expr
-                })
-            })
+        if !attrs.is_empty()
+            && let Ok(expr) = &mut res
+        {
+            mem::swap(&mut expr.attrs, &mut attrs);
+            expr.attrs.extend(attrs)
         }
+        res
     }
 
     pub(super) fn parse_dot_suffix_expr(
@@ -2647,10 +2633,7 @@ impl<'a> Parser<'a> {
             self.expect(&token::Eq)?;
         }
         let attrs = self.parse_outer_attributes()?;
-        let expr = self.parse_expr_assoc_with(
-            1 + prec_let_scrutinee_needs_par(),
-            LhsExpr::Unparsed { attrs },
-        )?;
+        let expr = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), attrs)?;
         let span = lo.to(expr.span);
         Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered)))
     }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index e01f605722b..4b8e4c25e16 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -192,24 +192,54 @@ struct ClosureSpans {
     body: Span,
 }
 
-/// Indicates a range of tokens that should be replaced by
-/// the tokens in the provided `AttrsTarget`. This is used in two
-/// places during token collection:
+/// A token range within a `Parser`'s full token stream.
+#[derive(Clone, Debug)]
+struct ParserRange(Range<u32>);
+
+/// A token range within an individual AST node's (lazy) token stream, i.e.
+/// relative to that node's first token. Distinct from `ParserRange` so the two
+/// kinds of range can't be mixed up.
+#[derive(Clone, Debug)]
+struct NodeRange(Range<u32>);
+
+/// Indicates a range of tokens that should be replaced by an `AttrsTarget`
+/// (replacement) or be replaced by nothing (deletion). This is used in two
+/// places during token collection.
+///
+/// 1. Replacement. During the parsing of an AST node that may have a
+///    `#[derive]` attribute, when we parse a nested AST node that has `#[cfg]`
+///    or `#[cfg_attr]`, we replace the entire inner AST node with
+///    `FlatToken::AttrsTarget`. This lets us perform eager cfg-expansion on an
+///    `AttrTokenStream`.
 ///
-/// 1. During the parsing of an AST node that may have a `#[derive]`
-/// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]`
-/// In this case, we use a `ReplaceRange` to replace the entire inner AST node
-/// with `FlatToken::AttrsTarget`, allowing us to perform eager cfg-expansion
-/// on an `AttrTokenStream`.
+/// 2. Deletion. We delete inner attributes from all collected token streams,
+///    and instead track them through the `attrs` field on the AST node. This
+///    lets us manipulate them similarly to outer attributes. When we create a
+///    `TokenStream`, the inner attributes are inserted into the proper place
+///    in the token stream.
 ///
-/// 2. When we parse an inner attribute while collecting tokens. We
-/// remove inner attributes from the token stream entirely, and
-/// instead track them through the `attrs` field on the AST node.
-/// This allows us to easily manipulate them (for example, removing
-/// the first macro inner attribute to invoke a proc-macro).
-/// When create a `TokenStream`, the inner attributes get inserted
-/// into the proper place in the token stream.
-type ReplaceRange = (Range<u32>, Option<AttrsTarget>);
+/// Each replacement starts off in `ParserReplacement` form but is converted to
+/// `NodeReplacement` form when it is attached to a single AST node, via
+/// `LazyAttrTokenStreamImpl`.
+type ParserReplacement = (ParserRange, Option<AttrsTarget>);
+
+/// See the comment on `ParserReplacement`.
+type NodeReplacement = (NodeRange, Option<AttrsTarget>);
+
+impl NodeRange {
+    // Converts a range within a parser's tokens to a range within a
+    // node's tokens beginning at `start_pos`.
+    //
+    // For example, imagine a parser with 50 tokens in its token stream, a
+    // function that spans `ParserRange(20..40)` and an inner attribute within
+    // that function that spans `ParserRange(30..35)`. We would find the inner
+    // attribute's range within the function's tokens by subtracting 20, which
+    // is the position of the function's start token. This gives
+    // `NodeRange(10..15)`.
+    fn new(ParserRange(parser_range): ParserRange, start_pos: u32) -> NodeRange {
+        NodeRange((parser_range.start - start_pos)..(parser_range.end - start_pos))
+    }
+}
 
 /// Controls how we capture tokens. Capturing can be expensive,
 /// so we try to avoid performing capturing in cases where
@@ -226,8 +256,8 @@ enum Capturing {
 #[derive(Clone, Debug)]
 struct CaptureState {
     capturing: Capturing,
-    replace_ranges: Vec<ReplaceRange>,
-    inner_attr_ranges: FxHashMap<AttrId, Range<u32>>,
+    parser_replacements: Vec<ParserReplacement>,
+    inner_attr_parser_ranges: FxHashMap<AttrId, ParserRange>,
 }
 
 /// Iterator over a `TokenStream` that produces `Token`s. It's a bit odd that
@@ -417,8 +447,8 @@ impl<'a> Parser<'a> {
             subparser_name,
             capture_state: CaptureState {
                 capturing: Capturing::No,
-                replace_ranges: Vec::new(),
-                inner_attr_ranges: Default::default(),
+                parser_replacements: Vec::new(),
+                inner_attr_parser_ranges: Default::default(),
             },
             current_closure: None,
             recovery: Recovery::Allowed,
@@ -1220,9 +1250,6 @@ impl<'a> Parser<'a> {
         if self.eat_keyword_case(kw::Unsafe, case) {
             Safety::Unsafe(self.prev_token.uninterpolated_span())
         } else if self.eat_keyword_case(kw::Safe, case) {
-            self.psess
-                .gated_spans
-                .gate(sym::unsafe_extern_blocks, self.prev_token.uninterpolated_span());
             Safety::Safe(self.prev_token.uninterpolated_span())
         } else {
             Safety::Default
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index b6f85cc9032..5bfb8bdf776 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -25,7 +25,7 @@ use crate::errors::{
     UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
     UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
 };
-use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr};
+use crate::parser::expr::could_be_unclosed_char_literal;
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 
 #[derive(PartialEq, Copy, Clone)]
@@ -403,8 +403,9 @@ impl<'a> Parser<'a> {
 
             // Parse an associative expression such as `+ expr`, `% expr`, ...
             // Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
-            let lhs = LhsExpr::Parsed { expr, starts_statement: false };
-            if let Ok(expr) = snapshot.parse_expr_assoc_with(0, lhs).map_err(|err| err.cancel()) {
+            if let Ok(expr) =
+                snapshot.parse_expr_assoc_rest_with(0, false, expr).map_err(|err| err.cancel())
+            {
                 // We got a valid expression.
                 self.restore_snapshot(snapshot);
                 self.restrictions.remove(Restrictions::IS_PAT);
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 7b0daaa1433..a3b782d651d 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -17,7 +17,6 @@ use thin_vec::{thin_vec, ThinVec};
 
 use super::attr::InnerAttrForbiddenReason;
 use super::diagnostics::AttemptLocalParseRecovery;
-use super::expr::LhsExpr;
 use super::pat::{PatternLocation, RecoverComma};
 use super::path::PathStyle;
 use super::{
@@ -66,7 +65,12 @@ impl<'a> Parser<'a> {
         }
 
         Ok(Some(if self.token.is_keyword(kw::Let) {
-            self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
+            self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+                this.expect_keyword(kw::Let)?;
+                let local = this.parse_local(attrs)?;
+                let trailing = capture_semi && this.token.kind == token::Semi;
+                Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing))
+            })?
         } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
             self.recover_stmt_local_after_let(
                 lo,
@@ -112,13 +116,12 @@ impl<'a> Parser<'a> {
                 }
             }
         } else if let Some(item) = self.parse_item_common(
-            attrs.clone(),
+            attrs.clone(), // FIXME: unwanted clone of attrs
             false,
             true,
             FnParseMode { req_name: |_| true, req_body: true },
             force_collect,
         )? {
-            // FIXME: Bad copy of attrs
             self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
         } else if self.eat(&token::Semi) {
             // Do not attempt to parse an expression if we're done here.
@@ -173,7 +176,7 @@ impl<'a> Parser<'a> {
             // Perform this outside of the `collect_tokens_trailing_token` closure,
             // since our outer attributes do not apply to this part of the expression
             let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
-                this.parse_expr_assoc_with(0, LhsExpr::Parsed { expr, starts_statement: true })
+                this.parse_expr_assoc_rest_with(0, true, expr)
             })?;
             Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
         } else {
@@ -206,8 +209,7 @@ impl<'a> Parser<'a> {
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
             let e = self.maybe_recover_from_bad_qpath(e)?;
             let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
-            let e = self
-                .parse_expr_assoc_with(0, LhsExpr::Parsed { expr: e, starts_statement: false })?;
+            let e = self.parse_expr_assoc_rest_with(0, false, e)?;
             StmtKind::Expr(e)
         };
         Ok(self.mk_stmt(lo.to(hi), kind))
@@ -247,21 +249,6 @@ impl<'a> Parser<'a> {
         Ok(stmt)
     }
 
-    fn parse_local_mk(
-        &mut self,
-        lo: Span,
-        attrs: AttrWrapper,
-        capture_semi: bool,
-        force_collect: ForceCollect,
-    ) -> PResult<'a, Stmt> {
-        self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
-            this.expect_keyword(kw::Let)?;
-            let local = this.parse_local(attrs)?;
-            let trailing = capture_semi && this.token.kind == token::Semi;
-            Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing))
-        })
-    }
-
     /// Parses a local variable declaration.
     fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_token.span;
@@ -421,10 +408,14 @@ impl<'a> Parser<'a> {
     fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>> {
         let eq_consumed = match self.token.kind {
             token::BinOpEq(..) => {
-                // Recover `let x <op>= 1` as `let x = 1`
+                // Recover `let x <op>= 1` as `let x = 1` We must not use `+ BytePos(1)` here
+                // because `<op>` can be a multi-byte lookalike that was recovered, e.g. `➖=` (the
+                // `➖` is a U+2796 Heavy Minus Sign Unicode Character) that was recovered as a
+                // `-=`.
+                let extra_op_span = self.psess.source_map().start_point(self.token.span);
                 self.dcx().emit_err(errors::CompoundAssignmentExpressionInLet {
                     span: self.token.span,
-                    suggestion: self.token.span.with_hi(self.token.span.lo() + BytePos(1)),
+                    suggestion: extra_op_span,
                 });
                 self.bump();
                 true
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 1747307a1b2..59c9d1e49f5 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -100,6 +100,10 @@ passes_continue_labeled_block =
     .label = labeled blocks cannot be `continue`'d
     .block_label = labeled block the `continue` points to
 
+passes_coroutine_on_non_closure =
+    attribute should be applied to closures
+    .label = not a closure
+
 passes_coverage_not_fn_or_closure =
     attribute should be applied to a function definition or closure
     .label = not a function or closure
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 86b18570f37..c8d4c190113 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -20,13 +20,13 @@ use rustc_hir::{
     TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
 };
 use rustc_macros::LintDiagnostic;
-use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
@@ -116,130 +116,185 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
             match attr.path().as_slice() {
-                [sym::diagnostic, sym::do_not_recommend] => {
+                [sym::diagnostic, sym::do_not_recommend, ..] => {
                     self.check_do_not_recommend(attr.span, hir_id, target)
                 }
-                [sym::diagnostic, sym::on_unimplemented] => {
+                [sym::diagnostic, sym::on_unimplemented, ..] => {
                     self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
                 }
-                [sym::inline] => self.check_inline(hir_id, attr, span, target),
-                [sym::coverage] => self.check_coverage(attr, span, target),
-                [sym::optimize] => self.check_optimize(hir_id, attr, target),
-                [sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target),
-                [sym::marker] => self.check_marker(hir_id, attr, span, target),
-                [sym::target_feature] => {
+                [sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
+                [sym::coverage, ..] => self.check_coverage(attr, span, target),
+                [sym::optimize, ..] => self.check_optimize(hir_id, attr, target),
+                [sym::no_sanitize, ..] => self.check_no_sanitize(hir_id, attr, span, target),
+                [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
+                [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
+                [sym::target_feature, ..] => {
                     self.check_target_feature(hir_id, attr, span, target, attrs)
                 }
-                [sym::thread_local] => self.check_thread_local(attr, span, target),
-                [sym::track_caller] => {
+                [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
+                [sym::track_caller, ..] => {
                     self.check_track_caller(hir_id, attr.span, attrs, span, target)
                 }
-                [sym::doc] => self.check_doc_attrs(
+                [sym::doc, ..] => self.check_doc_attrs(
                     attr,
                     hir_id,
                     target,
                     &mut specified_inline,
                     &mut doc_aliases,
                 ),
-                [sym::no_link] => self.check_no_link(hir_id, attr, span, target),
-                [sym::export_name] => self.check_export_name(hir_id, attr, span, target),
-                [sym::rustc_layout_scalar_valid_range_start]
-                | [sym::rustc_layout_scalar_valid_range_end] => {
+                [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
+                [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target),
+                [sym::rustc_layout_scalar_valid_range_start, ..]
+                | [sym::rustc_layout_scalar_valid_range_end, ..] => {
                     self.check_rustc_layout_scalar_valid_range(attr, span, target)
                 }
-                [sym::allow_internal_unstable] => {
+                [sym::allow_internal_unstable, ..] => {
                     self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
                 }
-                [sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target),
-                [sym::rustc_allow_const_fn_unstable] => {
+                [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
+                [sym::rustc_allow_const_fn_unstable, ..] => {
                     self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
                 }
-                [sym::rustc_std_internal_symbol] => {
+                [sym::rustc_std_internal_symbol, ..] => {
                     self.check_rustc_std_internal_symbol(attr, span, target)
                 }
-                [sym::naked] => self.check_naked(hir_id, attr, span, target, attrs),
-                [sym::rustc_never_returns_null_ptr] => {
+                [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
+                [sym::rustc_never_returns_null_ptr, ..] => {
                     self.check_applied_to_fn_or_method(hir_id, attr, span, target)
                 }
-                [sym::rustc_legacy_const_generics] => {
+                [sym::rustc_legacy_const_generics, ..] => {
                     self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
                 }
-                [sym::rustc_lint_query_instability] => {
+                [sym::rustc_lint_query_instability, ..] => {
                     self.check_rustc_lint_query_instability(hir_id, attr, span, target)
                 }
-                [sym::rustc_lint_diagnostics] => {
+                [sym::rustc_lint_diagnostics, ..] => {
                     self.check_rustc_lint_diagnostics(hir_id, attr, span, target)
                 }
-                [sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target),
-                [sym::rustc_lint_opt_deny_field_access] => {
+                [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
+                [sym::rustc_lint_opt_deny_field_access, ..] => {
                     self.check_rustc_lint_opt_deny_field_access(attr, span, target)
                 }
-                [sym::rustc_clean]
-                | [sym::rustc_dirty]
-                | [sym::rustc_if_this_changed]
-                | [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr),
-                [sym::rustc_coinductive]
-                | [sym::rustc_must_implement_one_of]
-                | [sym::rustc_deny_explicit_impl]
-                | [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target),
-                [sym::cmse_nonsecure_entry] => {
+                [sym::rustc_clean, ..]
+                | [sym::rustc_dirty, ..]
+                | [sym::rustc_if_this_changed, ..]
+                | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
+                [sym::rustc_coinductive, ..]
+                | [sym::rustc_must_implement_one_of, ..]
+                | [sym::rustc_deny_explicit_impl, ..]
+                | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
+                [sym::cmse_nonsecure_entry, ..] => {
                     self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
                 }
-                [sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target),
-                [sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target),
-                [sym::must_use] => self.check_must_use(hir_id, attr, target),
-                [sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target),
-                [sym::rustc_allow_incoherent_impl] => {
+                [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
+                [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
+                [sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
+                [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
+                [sym::rustc_allow_incoherent_impl, ..] => {
                     self.check_allow_incoherent_impl(attr, span, target)
                 }
-                [sym::rustc_has_incoherent_inherent_impls] => {
+                [sym::rustc_has_incoherent_inherent_impls, ..] => {
                     self.check_has_incoherent_inherent_impls(attr, span, target)
                 }
-                [sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target),
-                [sym::ffi_const] => self.check_ffi_const(attr.span, target),
-                [sym::rustc_const_unstable]
-                | [sym::rustc_const_stable]
-                | [sym::unstable]
-                | [sym::stable]
-                | [sym::rustc_allowed_through_unstable_modules]
-                | [sym::rustc_promotable] => self.check_stability_promotable(attr, target),
-                [sym::link_ordinal] => self.check_link_ordinal(attr, span, target),
-                [sym::rustc_confusables] => self.check_confusables(attr, target),
-                [sym::rustc_safe_intrinsic] => {
+                [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span, attrs, target),
+                [sym::ffi_const, ..] => self.check_ffi_const(attr.span, target),
+                [sym::rustc_const_unstable, ..]
+                | [sym::rustc_const_stable, ..]
+                | [sym::unstable, ..]
+                | [sym::stable, ..]
+                | [sym::rustc_allowed_through_unstable_modules, ..]
+                | [sym::rustc_promotable, ..] => self.check_stability_promotable(attr, target),
+                [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
+                [sym::rustc_confusables, ..] => self.check_confusables(attr, target),
+                [sym::rustc_safe_intrinsic, ..] => {
                     self.check_rustc_safe_intrinsic(hir_id, attr, span, target)
                 }
-                [sym::cold] => self.check_cold(hir_id, attr, span, target),
-                [sym::link] => self.check_link(hir_id, attr, span, target),
-                [sym::link_name] => self.check_link_name(hir_id, attr, span, target),
-                [sym::link_section] => self.check_link_section(hir_id, attr, span, target),
-                [sym::no_mangle] => self.check_no_mangle(hir_id, attr, span, target),
-                [sym::deprecated] => self.check_deprecated(hir_id, attr, span, target),
-                [sym::macro_use] | [sym::macro_escape] => {
+                [sym::cold, ..] => self.check_cold(hir_id, attr, span, target),
+                [sym::link, ..] => self.check_link(hir_id, attr, span, target),
+                [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
+                [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
+                [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target),
+                [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target),
+                [sym::macro_use, ..] | [sym::macro_escape, ..] => {
                     self.check_macro_use(hir_id, attr, target)
                 }
-                [sym::path] => self.check_generic_attr(hir_id, attr, target, Target::Mod),
-                [sym::macro_export] => self.check_macro_export(hir_id, attr, target),
-                [sym::ignore] | [sym::should_panic] => {
+                [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod),
+                [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
+                [sym::ignore, ..] | [sym::should_panic, ..] => {
                     self.check_generic_attr(hir_id, attr, target, Target::Fn)
                 }
-                [sym::automatically_derived] => {
+                [sym::automatically_derived, ..] => {
                     self.check_generic_attr(hir_id, attr, target, Target::Impl)
                 }
-                [sym::no_implicit_prelude] => {
+                [sym::no_implicit_prelude, ..] => {
                     self.check_generic_attr(hir_id, attr, target, Target::Mod)
                 }
-                [sym::rustc_object_lifetime_default] => self.check_object_lifetime_default(hir_id),
-                [sym::proc_macro] => {
+                [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id),
+                [sym::proc_macro, ..] => {
                     self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
                 }
-                [sym::proc_macro_attribute] => {
+                [sym::proc_macro_attribute, ..] => {
                     self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
                 }
-                [sym::proc_macro_derive] => {
+                [sym::proc_macro_derive, ..] => {
                     self.check_generic_attr(hir_id, attr, target, Target::Fn);
                     self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
                 }
-                _ => {}
+                [sym::coroutine, ..] => {
+                    self.check_coroutine(attr, target);
+                }
+                [
+                    // ok
+                    sym::allow
+                    | sym::expect
+                    | sym::warn
+                    | sym::deny
+                    | sym::forbid
+                    | sym::cfg
+                    | sym::cfg_attr
+                    // need to be fixed
+                    | sym::cfi_encoding // FIXME(cfi_encoding)
+                    | sym::may_dangle // FIXME(dropck_eyepatch)
+                    | sym::pointee // FIXME(derive_smart_pointer)
+                    | sym::linkage // FIXME(linkage)
+                    | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
+                    | sym::used // handled elsewhere to restrict to static items
+                    | sym::repr // handled elsewhere to restrict to type decls items
+                    | sym::instruction_set // broken on stable!!!
+                    | sym::windows_subsystem // broken on stable!!!
+                    | sym::patchable_function_entry // FIXME(patchable_function_entry)
+                    | sym::deprecated_safe // FIXME(deprecated_safe)
+                    // internal
+                    | sym::prelude_import
+                    | sym::panic_handler
+                    | sym::allow_internal_unsafe
+                    | sym::fundamental
+                    | sym::lang
+                    | sym::needs_allocator
+                    | sym::default_lib_allocator
+                    | sym::start
+                    | sym::custom_mir,
+                    ..
+                ] => {}
+                [name, ..] => {
+                    match BUILTIN_ATTRIBUTE_MAP.get(name) {
+                        // checked below
+                        Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
+                        Some(_) => {
+                            // FIXME: differentiate between unstable and internal attributes just
+                            // like we do with features instead of just accepting `rustc_`
+                            // attributes by name. That should allow trimming the above list, too.
+                            if !name.as_str().starts_with("rustc_") {
+                                span_bug!(
+                                    attr.span,
+                                    "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
+                                )
+                            }
+                        }
+                        None => (),
+                    }
+                }
+                [] => unreachable!(),
             }
 
             let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
@@ -376,6 +431,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 
     /// Checks that `#[optimize(..)]` is applied to a function/closure/method,
     /// or to an impl block or module.
+    // FIXME(#128488): this should probably be elevated to an error?
     fn check_optimize(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         match target {
             Target::Fn
@@ -395,6 +451,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
+    /// Checks that `#[no_sanitize(..)]` is applied to a function or method.
+    fn check_no_sanitize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+        self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+    }
+
     fn check_generic_attr(
         &self,
         hir_id: HirId,
@@ -2279,6 +2340,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             self.abort.set(true);
         }
     }
+
+    fn check_coroutine(&self, attr: &Attribute, target: Target) {
+        match target {
+            Target::Closure => return,
+            _ => {
+                self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span });
+            }
+        }
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 8a931fc4158..7ae5c904004 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -17,7 +17,7 @@ use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_session::lint::builtin::DEAD_CODE;
@@ -44,79 +44,16 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     )
 }
 
-struct Publicness {
-    ty_is_public: bool,
-    ty_and_all_fields_are_public: bool,
-}
-
-impl Publicness {
-    fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self {
-        Self { ty_is_public, ty_and_all_fields_are_public }
-    }
-}
-
-fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
-    match ty.kind {
-        TyKind::Path(hir::QPath::Resolved(_, path)) => {
-            if let Res::Def(def_kind, def_id) = path.res
-                && let Some(local_def_id) = def_id.as_local()
-            {
-                Some((local_def_id, def_kind))
-            } else {
-                None
-            }
-        }
-        TyKind::Slice(ty) | TyKind::Array(ty, _) => adt_of(ty),
-        TyKind::Ptr(ty) | TyKind::Ref(_, ty) => adt_of(ty.ty),
-        _ => None,
-    }
-}
-
-fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool {
-    let adt_def = tcx.adt_def(id);
-
-    // skip types contain fields of unit and never type,
-    // it's usually intentional to make the type not constructible
-    let not_require_constructor = adt_def.all_fields().any(|field| {
-        let field_type = tcx.type_of(field.did).instantiate_identity();
-        field_type.is_unit() || field_type.is_never()
-    });
-
-    not_require_constructor
-        || adt_def.all_fields().all(|field| {
-            let field_type = tcx.type_of(field.did).instantiate_identity();
-            // skip fields of PhantomData,
-            // cause it's a common way to check things like well-formedness
-            if field_type.is_phantom_data() {
-                return true;
-            }
-
-            field.vis.is_public()
-        })
-}
-
-/// check struct and its fields are public or not,
-/// for enum and union, just check they are public,
-/// and doesn't solve types like &T for now, just skip them
-fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness {
-    if let Some((def_id, def_kind)) = adt_of(ty) {
-        return match def_kind {
-            DefKind::Enum | DefKind::Union => {
-                let ty_is_public = tcx.visibility(def_id).is_public();
-                Publicness::new(ty_is_public, ty_is_public)
-            }
-            DefKind::Struct => {
-                let ty_is_public = tcx.visibility(def_id).is_public();
-                Publicness::new(
-                    ty_is_public,
-                    ty_is_public && struct_all_fields_are_public(tcx, def_id),
-                )
-            }
-            _ => Publicness::new(true, true),
-        };
+fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool {
+    if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
+        && let Res::Def(def_kind, def_id) = path.res
+        && def_id.is_local()
+        && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
+    {
+        tcx.visibility(def_id).is_public()
+    } else {
+        true
     }
-
-    Publicness::new(true, true)
 }
 
 /// Determine if a work from the worklist is coming from a `#[allow]`
@@ -172,10 +109,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
 
     fn handle_res(&mut self, res: Res) {
         match res {
-            Res::Def(
-                DefKind::Const | DefKind::AssocConst | DefKind::AssocTy | DefKind::TyAlias,
-                def_id,
-            ) => {
+            Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => {
                 self.check_def_id(def_id);
             }
             _ if self.in_pat => {}
@@ -294,10 +228,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         pats: &[hir::PatField<'_>],
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
-            ty::Adt(adt, _) => {
-                self.check_def_id(adt.did());
-                adt.variant_of_res(res)
-            }
+            ty::Adt(adt, _) => adt.variant_of_res(res),
             _ => span_bug!(lhs.span, "non-ADT in struct pattern"),
         };
         for pat in pats {
@@ -317,10 +248,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         dotdot: hir::DotDotPos,
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
-            ty::Adt(adt, _) => {
-                self.check_def_id(adt.did());
-                adt.variant_of_res(res)
-            }
+            ty::Adt(adt, _) => adt.variant_of_res(res),
             _ => {
                 self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
                 return;
@@ -425,6 +353,31 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 return false;
             }
 
+            // don't ignore impls for Enums and pub Structs whose methods don't have self receiver,
+            // cause external crate may call such methods to construct values of these types
+            if let Some(local_impl_of) = impl_of.as_local()
+                && let Some(local_def_id) = def_id.as_local()
+                && let Some(fn_sig) =
+                    self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
+                && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
+                && let TyKind::Path(hir::QPath::Resolved(_, path)) =
+                    self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind
+                && let Res::Def(def_kind, did) = path.res
+            {
+                match def_kind {
+                    // for example, #[derive(Default)] pub struct T(i32);
+                    // external crate can call T::default() to construct T,
+                    // so that don't ignore impl Default for pub Enum and Structs
+                    DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => {
+                        return false;
+                    }
+                    // don't ignore impl Default for Enums,
+                    // cause we don't know which variant is constructed
+                    DefKind::Enum => return false,
+                    _ => (),
+                };
+            }
+
             if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
                 && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
             {
@@ -467,7 +420,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                     intravisit::walk_item(self, item)
                 }
                 hir::ItemKind::ForeignMod { .. } => {}
-                hir::ItemKind::Trait(_, _, _, _, trait_item_refs) => {
+                hir::ItemKind::Trait(..) => {
                     for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) {
                         if let Some(local_def_id) = impl_def_id.as_local()
                             && let ItemKind::Impl(impl_ref) =
@@ -480,12 +433,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                             intravisit::walk_path(self, impl_ref.of_trait.unwrap().path);
                         }
                     }
-                    // mark assoc ty live if the trait is live
-                    for trait_item in trait_item_refs {
-                        if let hir::AssocItemKind::Type = trait_item.kind {
-                            self.check_def_id(trait_item.id.owner_id.to_def_id());
-                        }
-                    }
+
                     intravisit::walk_item(self, item)
                 }
                 _ => intravisit::walk_item(self, item),
@@ -502,12 +450,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                             && let ItemKind::Impl(impl_ref) =
                                 self.tcx.hir().expect_item(local_impl_id).kind
                         {
-                            if !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
-                                .ty_and_all_fields_are_public
+                            if !matches!(trait_item.kind, hir::TraitItemKind::Type(..))
+                                && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
                             {
-                                // skip impl-items of non pure pub ty,
-                                // cause we don't know the ty is constructed or not,
-                                // check these later in `solve_rest_impl_items`
+                                // skip methods of private ty,
+                                // they would be solved in `solve_rest_impl_items`
                                 continue;
                             }
 
@@ -582,25 +529,28 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
     }
 
     fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool {
-        if let Some((local_def_id, def_kind)) =
-            adt_of(self.tcx.hir().item(impl_id).expect_impl().self_ty)
+        if let TyKind::Path(hir::QPath::Resolved(_, path)) =
+            self.tcx.hir().item(impl_id).expect_impl().self_ty.kind
+            && let Res::Def(def_kind, def_id) = path.res
+            && let Some(local_def_id) = def_id.as_local()
             && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
         {
+            if self.tcx.visibility(impl_item_id).is_public() {
+                // for the public method, we don't know the trait item is used or not,
+                // so we mark the method live if the self is used
+                return self.live_symbols.contains(&local_def_id);
+            }
+
             if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
                 && let Some(local_id) = trait_item_id.as_local()
             {
-                // for the local impl item, we can know the trait item is used or not,
+                // for the private method, we can know the trait item is used or not,
                 // so we mark the method live if the self is used and the trait item is used
-                self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id)
-            } else {
-                // for the foreign method and inherent pub method,
-                // we don't know the trait item or the method is used or not,
-                // so we mark the method live if the self is used
-                self.live_symbols.contains(&local_def_id)
+                return self.live_symbols.contains(&local_id)
+                    && self.live_symbols.contains(&local_def_id);
             }
-        } else {
-            false
         }
+        false
     }
 }
 
@@ -686,9 +636,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
                 self.handle_field_pattern_match(pat, res, fields);
             }
             PatKind::Path(ref qpath) => {
-                if let ty::Adt(adt, _) = self.typeck_results().node_type(pat.hir_id).kind() {
-                    self.check_def_id(adt.did());
-                }
                 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
                 self.handle_res(res);
             }
@@ -825,9 +772,7 @@ fn check_item<'tcx>(
                 .iter()
                 .filter_map(|def_id| def_id.as_local());
 
-            let self_ty = tcx.hir().item(id).expect_impl().self_ty;
-            let Publicness { ty_is_public, ty_and_all_fields_are_public } =
-                ty_ref_to_pub_struct(tcx, self_ty);
+            let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty);
 
             // And we access the Map here to get HirId from LocalDefId
             for local_def_id in local_def_ids {
@@ -843,19 +788,18 @@ fn check_item<'tcx>(
                 // for trait impl blocks,
                 // mark the method live if the self_ty is public,
                 // or the method is public and may construct self
-                if tcx.visibility(local_def_id).is_public()
-                    && (ty_and_all_fields_are_public || (ty_is_public && may_construct_self))
+                if of_trait
+                    && (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn)
+                        || tcx.visibility(local_def_id).is_public()
+                            && (ty_is_pub || may_construct_self))
                 {
-                    // if the impl item is public,
-                    // and the ty may be constructed or can be constructed in foreign crates,
-                    // mark the impl item live
                     worklist.push((local_def_id, ComesFromAllowExpect::No));
                 } else if let Some(comes_from_allow) =
                     has_allow_dead_code_or_lang_attr(tcx, local_def_id)
                 {
                     worklist.push((local_def_id, comes_from_allow));
-                } else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public {
-                    // private impl items of traits || public impl items not constructs self
+                } else if of_trait {
+                    // private method || public method not constructs self
                     unsolved_impl_items.push((id, local_def_id));
                 }
             }
@@ -881,13 +825,10 @@ fn check_trait_item(
     worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>,
     id: hir::TraitItemId,
 ) {
-    use hir::TraitItemKind::{Const, Fn, Type};
-    if matches!(
-        tcx.def_kind(id.owner_id),
-        DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn
-    ) {
+    use hir::TraitItemKind::{Const, Fn};
+    if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
         let trait_item = tcx.hir().trait_item(id);
-        if matches!(trait_item.kind, Const(_, Some(_)) | Type(_, Some(_)) | Fn(..))
+        if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..))
             && let Some(comes_from_allow) =
                 has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
         {
@@ -925,14 +866,6 @@ fn create_and_seed_worklist(
             effective_vis
                 .is_public_at_level(Level::Reachable)
                 .then_some(id)
-                .filter(|&id|
-                    // checks impls, impl-items and pub structs with all public fields later
-                    match tcx.def_kind(id) {
-                        DefKind::Impl { .. } => false,
-                        DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
-                        DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(),
-                        _ => true
-                    })
                 .map(|id| (id, ComesFromAllowExpect::No))
         })
         // Seed entry point
@@ -1216,7 +1149,6 @@ impl<'tcx> DeadVisitor<'tcx> {
         }
         match self.tcx.def_kind(def_id) {
             DefKind::AssocConst
-            | DefKind::AssocTy
             | DefKind::AssocFn
             | DefKind::Fn
             | DefKind::Static { .. }
@@ -1258,14 +1190,10 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
             || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id))
         {
             for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) {
-                // We have diagnosed unused assocs in traits
+                // We have diagnosed unused methods in traits
                 if matches!(def_kind, DefKind::Impl { of_trait: true })
-                    && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn)
-                    // skip unused public inherent methods,
-                    // cause we have diagnosed unconstructed struct
-                    || matches!(def_kind, DefKind::Impl { of_trait: false })
-                        && tcx.visibility(def_id).is_public()
-                        && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public
+                    && tcx.def_kind(def_id) == DefKind::AssocFn
+                    || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn
                 {
                     continue;
                 }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index c4f3c8a0d6c..36dfc40e762 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -637,6 +637,13 @@ pub struct Confusables {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_coroutine_on_non_closure)]
+pub struct CoroutineOnNonClosure {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_empty_confusables)]
 pub(crate) struct EmptyConfusables {
     #[primary_span]
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index a5c0b13c90b..e37fa072b6d 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -54,7 +54,6 @@ pub trait PatCx: Sized + fmt::Debug {
     type PatData: Clone;
 
     fn is_exhaustive_patterns_feature_on(&self) -> bool;
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool;
 
     /// The number of fields for this constructor.
     fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize;
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 6290aeb2523..25f7cc17c11 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -237,9 +237,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
                             let is_visible =
                                 adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
-                            let is_uninhabited = (cx.tcx.features().exhaustive_patterns
-                                || cx.tcx.features().min_exhaustive_patterns)
-                                && cx.is_uninhabited(*ty);
+                            let is_uninhabited = cx.is_uninhabited(*ty);
                             let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
                             (ty, PrivateUninhabitedField(skip))
                         });
@@ -925,9 +923,6 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
     fn is_exhaustive_patterns_feature_on(&self) -> bool {
         self.tcx.features().exhaustive_patterns
     }
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
-        self.tcx.features().min_exhaustive_patterns
-    }
 
     fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
         self.ctor_arity(ctor, *ty)
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 9710c9e1303..6535afcc398 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -543,13 +543,11 @@
 //! recurse into subpatterns. That second part is done through [`PlaceValidity`], most notably
 //! [`PlaceValidity::specialize`].
 //!
-//! Having said all that, in practice we don't fully follow what's been presented in this section.
-//! Let's call "toplevel exception" the case where the match scrutinee itself has type `!` or
-//! `EmptyEnum`. First, on stable rust, we require `_` patterns for empty types in all cases apart
-//! from the toplevel exception. The `exhaustive_patterns` and `min_exaustive_patterns` allow
-//! omitting patterns in the cases described above. There's a final detail: in the toplevel
-//! exception or with the `exhaustive_patterns` feature, we ignore place validity when checking
-//! whether a pattern is required for exhaustiveness. I (Nadrieril) hope to deprecate this behavior.
+//! Having said all that, we don't fully follow what's been presented in this section. For
+//! backwards-compatibility, we ignore place validity when checking whether a pattern is required
+//! for exhaustiveness in two cases: when the `exhaustive_patterns` feature gate is on, or when the
+//! match scrutinee itself has type `!` or `EmptyEnum`. I (Nadrieril) hope to deprecate this
+//! exception.
 //!
 //!
 //!
@@ -953,13 +951,10 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
             self.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
         // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
         // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
-        let empty_arms_are_unreachable = self.validity.is_known_valid()
-            && (is_toplevel_exception
-                || cx.is_exhaustive_patterns_feature_on()
-                || cx.is_min_exhaustive_patterns_feature_on());
+        let empty_arms_are_unreachable = self.validity.is_known_valid();
         // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
         // toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
-        let can_omit_empty_arms = empty_arms_are_unreachable
+        let can_omit_empty_arms = self.validity.is_known_valid()
             || is_toplevel_exception
             || cx.is_exhaustive_patterns_feature_on();
 
diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs
index 01a56eaa78f..ec0bcd43ad2 100644
--- a/compiler/rustc_pattern_analysis/tests/common/mod.rs
+++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs
@@ -152,10 +152,6 @@ impl PatCx for Cx {
         false
     }
 
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
-        true
-    }
-
     fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize {
         ty.sub_tys(ctor).len()
     }
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 761d6acdbae..ca3efc11201 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -588,7 +588,7 @@ pub fn report_cycle<'a>(
         cycle_stack,
         stack_bottom: stack[0].query.description.to_owned(),
         alias,
-        cycle_usage: cycle_usage,
+        cycle_usage,
         stack_count,
         note_span: (),
     };
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 2fa3692bb28..307625bcfb1 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -283,6 +283,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     parent_scope,
                     finalize.then(|| Finalize::new(id, path.span)),
                     None,
+                    None,
                 ) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
                         let res = module.res().expect("visibility resolved to unnamed block");
@@ -372,7 +373,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             has_attributes: !item.attrs.is_empty(),
             root_span,
             root_id,
-            vis: Cell::new(Some(vis)),
+            vis,
             used: Default::default(),
         });
 
@@ -888,7 +889,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             root_span: item.span,
             span: item.span,
             module_path: Vec::new(),
-            vis: Cell::new(Some(vis)),
+            vis,
             used: Cell::new(used.then_some(Used::Other)),
         });
         self.r.potentially_unused_imports.push(import);
@@ -1089,7 +1090,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 root_span: span,
                 span,
                 module_path: Vec::new(),
-                vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
+                vis: ty::Visibility::Restricted(CRATE_DEF_ID),
                 used: Default::default(),
             })
         };
@@ -1125,6 +1126,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     ident,
                     MacroNS,
                     &self.parent_scope,
+                    None,
                 );
                 if let Ok(binding) = result {
                     let import = macro_use_import(self, ident.span, false);
@@ -1253,7 +1255,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     root_span: span,
                     span,
                     module_path: Vec::new(),
-                    vis: Cell::new(Some(vis)),
+                    vis,
                     used: Cell::new(Some(Used::Other)),
                 });
                 let import_binding = self.r.import(binding, import);
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index a8199971561..75b8ecebdd9 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -382,7 +382,7 @@ impl Resolver<'_, '_> {
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
                 _ if import.used.get().is_some()
-                    || import.expect_vis().is_public()
+                    || import.vis.is_public()
                     || import.span.is_dummy() =>
                 {
                     if let ImportKind::MacroUse { .. } = import.kind {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 8080bb60e41..942026ef012 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1052,6 +1052,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 parent_scope,
                                 false,
                                 false,
+                                None,
                             ) {
                                 suggestions.extend(
                                     ext.helper_attrs
@@ -1506,6 +1507,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 None,
                 false,
                 None,
+                None,
             ) {
                 let desc = match binding.res() {
                     Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
@@ -1983,6 +1985,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
         module: Option<ModuleOrUniformRoot<'a>>,
         failed_segment_idx: usize,
         ident: Ident,
@@ -2066,11 +2069,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         parent_scope,
                         None,
                         ignore_binding,
+                        ignore_import,
                     )
                     .ok()
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
                 {
+                    assert!(ignore_import.is_none());
                     match self.resolve_ident_in_lexical_scope(
                         ident,
                         ns_to_try,
@@ -2091,6 +2096,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         None,
                         false,
                         ignore_binding,
+                        ignore_import,
                     )
                     .ok()
                 };
@@ -2132,6 +2138,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         } else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
             // Check whether the name refers to an item in the value namespace.
             let binding = if let Some(ribs) = ribs {
+                assert!(ignore_import.is_none());
                 self.resolve_ident_in_lexical_scope(
                     ident,
                     ValueNS,
@@ -2206,6 +2213,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 None,
                 false,
                 ignore_binding,
+                ignore_import,
             ) {
                 let descr = binding.res().descr();
                 (format!("{descr} `{ident}` is not a crate or module"), suggestion)
@@ -2259,7 +2267,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     ) -> Option<(Vec<Segment>, Option<String>)> {
         // Replace first ident with `self` and check if that is valid.
         path[0].ident.name = kw::SelfLower;
-        let result = self.maybe_resolve_path(&path, None, parent_scope);
+        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
         debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
     }
@@ -2278,7 +2286,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     ) -> Option<(Vec<Segment>, Option<String>)> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Crate;
-        let result = self.maybe_resolve_path(&path, None, parent_scope);
+        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
         debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
             Some((
@@ -2309,7 +2317,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     ) -> Option<(Vec<Segment>, Option<String>)> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Super;
-        let result = self.maybe_resolve_path(&path, None, parent_scope);
+        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
         debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
     }
@@ -2343,7 +2351,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         for name in extern_crate_names.into_iter() {
             // Replace first ident with a crate name and check if that is valid.
             path[0].ident.name = name;
-            let result = self.maybe_resolve_path(&path, None, parent_scope);
+            let result = self.maybe_resolve_path(&path, None, parent_scope, None);
             debug!(
                 "make_external_crate_suggestion: name={:?} path={:?} result={:?}",
                 name, path, result
@@ -2509,12 +2517,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     /// Finds a cfg-ed out item inside `module` with the matching name.
-    pub(crate) fn find_cfg_stripped(
-        &mut self,
-        err: &mut Diag<'_>,
-        segment: &Symbol,
-        module: DefId,
-    ) {
+    pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) {
         let local_items;
         let symbols = if module.is_local() {
             local_items = self
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 947ba569ab0..149c639efab 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -14,6 +14,7 @@ use Determinacy::*;
 use Namespace::*;
 
 use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
+use crate::imports::Import;
 use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
 use crate::macros::{sub_namespace_match, MacroRulesScope};
 use crate::{
@@ -351,6 +352,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 parent_scope,
                 finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
                 ignore_binding,
+                None,
             );
             if let Ok(binding) = item {
                 // The ident resolves to an item.
@@ -364,6 +366,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             finalize,
             finalize.is_some(),
             ignore_binding,
+            None,
         )
         .ok()
         .map(LexicalScopeBinding::Item)
@@ -383,6 +386,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         finalize: Option<Finalize>,
         force: bool,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, Determinacy> {
         bitflags::bitflags! {
             #[derive(Clone, Copy)]
@@ -455,6 +459,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 parent_scope,
                                 true,
                                 force,
+                                ignore_import,
                             ) {
                                 Ok((Some(ext), _)) => {
                                     if ext.helper_attrs.contains(&ident.name) {
@@ -496,6 +501,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             parent_scope,
                             finalize,
                             ignore_binding,
+                            ignore_import,
                         );
                         match binding {
                             Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
@@ -518,6 +524,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             !matches!(scope_set, ScopeSet::Late(..)),
                             finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
                             ignore_binding,
+                            ignore_import,
                         );
                         match binding {
                             Ok(binding) => {
@@ -585,6 +592,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 parent_scope,
                                 None,
                                 ignore_binding,
+                                ignore_import,
                             ) {
                                 if matches!(use_prelude, UsePrelude::Yes)
                                     || this.is_builtin_macro(binding.res())
@@ -738,8 +746,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None)
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None, ignore_import)
             .map_err(|(determinacy, _)| determinacy)
     }
 
@@ -752,9 +761,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         finalize: Option<Finalize>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize, ignore_binding)
-            .map_err(|(determinacy, _)| determinacy)
+        self.resolve_ident_in_module_ext(
+            module,
+            ident,
+            ns,
+            parent_scope,
+            finalize,
+            ignore_binding,
+            ignore_import,
+        )
+        .map_err(|(determinacy, _)| determinacy)
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -766,6 +784,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         finalize: Option<Finalize>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, (Determinacy, Weak)> {
         let tmp_parent_scope;
         let mut adjusted_parent_scope = parent_scope;
@@ -792,6 +811,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             false,
             finalize,
             ignore_binding,
+            ignore_import,
         )
     }
 
@@ -804,6 +824,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         finalize: Option<Finalize>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, Determinacy> {
         self.resolve_ident_in_module_unadjusted_ext(
             module,
@@ -813,6 +834,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             false,
             finalize,
             ignore_binding,
+            ignore_import,
         )
         .map_err(|(determinacy, _)| determinacy)
     }
@@ -831,6 +853,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // This binding should be ignored during in-module resolution, so that we don't get
         // "self-confirming" import resolutions during import validation and checking.
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<NameBinding<'a>, (Determinacy, Weak)> {
         let module = match module {
             ModuleOrUniformRoot::Module(module) => module,
@@ -843,6 +866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     finalize,
                     finalize.is_some(),
                     ignore_binding,
+                    ignore_import,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -879,6 +903,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     finalize,
                     finalize.is_some(),
                     ignore_binding,
+                    ignore_import,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -962,25 +987,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Check if one of single imports can still define the name,
         // if it can then our result is not determined and can be invalidated.
         for single_import in &resolution.single_imports {
-            let Some(import_vis) = single_import.vis.get() else {
-                // This branch handles a cycle in single imports, which occurs
-                // when we've previously **steal** the `vis` value during an import
-                // process.
+            if ignore_import == Some(*single_import) {
+                // This branch handles a cycle in single imports.
                 //
                 // For example:
                 // ```
                 // use a::b;
                 // use b as a;
                 // ```
-                // 1. Steal the `vis` in `use a::b` and attempt to locate `a` in the
+                // 1. Record `use a::b` as the `ignore_import` and attempt to locate `a` in the
                 //    current module.
                 // 2. Encounter the import `use b as a`, which is a `single_import` for `a`,
                 //    and try to find `b` in the current module.
                 // 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`.
                 //    This leads to entering this branch.
                 continue;
-            };
-            if !self.is_accessible_from(import_vis, parent_scope.module) {
+            }
+            if !self.is_accessible_from(single_import.vis, parent_scope.module) {
                 continue;
             }
             if let Some(ignored) = ignore_binding
@@ -1022,6 +1045,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 &single_import.parent_scope,
                 None,
                 ignore_binding,
+                ignore_import,
             ) {
                 Err(Determined) => continue,
                 Ok(binding)
@@ -1070,10 +1094,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Check if one of glob imports can still define the name,
         // if it can then our "no resolution" result is not determined and can be invalidated.
         for glob_import in module.globs.borrow().iter() {
-            let Some(import_vis) = glob_import.vis.get() else {
+            if ignore_import == Some(*glob_import) {
                 continue;
-            };
-            if !self.is_accessible_from(import_vis, parent_scope.module) {
+            }
+            if !self.is_accessible_from(glob_import.vis, parent_scope.module) {
                 continue;
             }
             let module = match glob_import.imported_module.get() {
@@ -1100,6 +1124,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 adjusted_parent_scope,
                 None,
                 ignore_binding,
+                ignore_import,
             );
 
             match result {
@@ -1412,8 +1437,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
+        ignore_import: Option<Import<'a>>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None)
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import)
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -1424,8 +1450,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         finalize: Option<Finalize>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, ignore_binding)
+        self.resolve_path_with_ribs(
+            path,
+            opt_ns,
+            parent_scope,
+            finalize,
+            None,
+            ignore_binding,
+            ignore_import,
+        )
     }
 
     pub(crate) fn resolve_path_with_ribs(
@@ -1436,6 +1471,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         finalize: Option<Finalize>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
         ignore_binding: Option<NameBinding<'a>>,
+        ignore_import: Option<Import<'a>>,
     ) -> PathResult<'a> {
         let mut module = None;
         let mut allow_super = true;
@@ -1538,10 +1574,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     parent_scope,
                     finalize,
                     ignore_binding,
+                    ignore_import,
                 )
             } else if let Some(ribs) = ribs
                 && let Some(TypeNS | ValueNS) = opt_ns
             {
+                assert!(ignore_import.is_none());
                 match self.resolve_ident_in_lexical_scope(
                     ident,
                     ns,
@@ -1570,6 +1608,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     finalize,
                     finalize.is_some(),
                     ignore_binding,
+                    ignore_import,
                 )
             };
 
@@ -1644,6 +1683,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             parent_scope,
                             ribs,
                             ignore_binding,
+                            ignore_import,
                             module,
                             segment_idx,
                             ident,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 0fa5cde9424..4a891d12281 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -48,6 +48,7 @@ pub(crate) enum ImportKind<'a> {
         /// `source` in `use prefix::source as target`.
         source: Ident,
         /// `target` in `use prefix::source as target`.
+        /// It will directly use `source` when the format is `use prefix::source`.
         target: Ident,
         /// Bindings to which `source` refers to.
         source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
@@ -174,7 +175,7 @@ pub(crate) struct ImportData<'a> {
     pub module_path: Vec<Segment>,
     /// The resolution of `module_path`.
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
-    pub vis: Cell<Option<ty::Visibility>>,
+    pub vis: ty::Visibility,
     pub used: Cell<Option<Used>>,
 }
 
@@ -194,10 +195,6 @@ impl<'a> ImportData<'a> {
         }
     }
 
-    pub(crate) fn expect_vis(&self) -> ty::Visibility {
-        self.vis.get().expect("encountered cleared import visibility")
-    }
-
     pub(crate) fn id(&self) -> Option<NodeId> {
         match self.kind {
             ImportKind::Single { id, .. }
@@ -266,7 +263,7 @@ fn pub_use_of_private_extern_crate_hack(
     match (&import.kind, &binding.kind) {
         (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. })
             if let ImportKind::ExternCrate { id, .. } = binding_import.kind
-                && import.expect_vis().is_public() =>
+                && import.vis.is_public() =>
         {
             Some(id)
         }
@@ -278,7 +275,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     /// Given a binding and an import that resolves to it,
     /// return the corresponding binding defined by the import.
     pub(crate) fn import(&self, binding: NameBinding<'a>, import: Import<'a>) -> NameBinding<'a> {
-        let import_vis = import.expect_vis().to_def_id();
+        let import_vis = import.vis.to_def_id();
         let vis = if binding.vis.is_at_least(import_vis, self.tcx)
             || pub_use_of_private_extern_crate_hack(import, binding).is_some()
         {
@@ -772,11 +769,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let module = if let Some(module) = import.imported_module.get() {
             module
         } else {
-            // For better failure detection, pretend that the import will
-            // not define any names while resolving its module path.
-            let orig_vis = import.vis.take();
-            let path_res = self.maybe_resolve_path(&import.module_path, None, &import.parent_scope);
-            import.vis.set(orig_vis);
+            let path_res = self.maybe_resolve_path(
+                &import.module_path,
+                None,
+                &import.parent_scope,
+                Some(import),
+            );
 
             match path_res {
                 PathResult::Module(module) => module,
@@ -806,16 +804,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         self.per_ns(|this, ns| {
             if !type_ns_only || ns == TypeNS {
                 if let Err(Undetermined) = source_bindings[ns].get() {
-                    // For better failure detection, pretend that the import will
-                    // not define any names while resolving its module path.
-                    let orig_vis = import.vis.take();
                     let binding = this.maybe_resolve_ident_in_module(
                         module,
                         source,
                         ns,
                         &import.parent_scope,
+                        Some(import),
                     );
-                    import.vis.set(orig_vis);
                     source_bindings[ns].set(binding);
                 } else {
                     return;
@@ -854,7 +849,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     /// Optionally returns an unresolved import error. This error is buffered and used to
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: Import<'a>) -> Option<UnresolvedImportError> {
-        let orig_vis = import.vis.take();
         let ignore_binding = match &import.kind {
             ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
             _ => None,
@@ -873,11 +867,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             &import.parent_scope,
             Some(finalize),
             ignore_binding,
+            Some(import),
         );
 
         let no_ambiguity =
             ambiguity_errors_len(&self.ambiguity_errors) == prev_ambiguity_errors_len;
-        import.vis.set(orig_vis);
+
         let module = match path_res {
             PathResult::Module(module) => {
                 // Consistency checks, analogous to `finalize_macro_resolutions`.
@@ -1012,8 +1007,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                     if !is_prelude
                         && let Some(max_vis) = max_vis.get()
-                        && let import_vis = import.expect_vis()
-                        && !max_vis.is_at_least(import_vis, self.tcx)
+                        && !max_vis.is_at_least(import.vis, self.tcx)
                     {
                         let def_id = self.local_def_id(id);
                         self.lint_buffer.buffer_lint(
@@ -1022,7 +1016,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             import.span,
                             BuiltinLintDiag::RedundantImportVisibility {
                                 max_vis: max_vis.to_string(def_id, self.tcx),
-                                import_vis: import_vis.to_string(def_id, self.tcx),
+                                import_vis: import.vis.to_string(def_id, self.tcx),
                                 span: import.span,
                             },
                         );
@@ -1037,9 +1031,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             // importing it if available.
             let mut path = import.module_path.clone();
             path.push(Segment::from_ident(ident));
-            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                self.resolve_path(&path, None, &import.parent_scope, Some(finalize), ignore_binding)
-            {
+            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(
+                &path,
+                None,
+                &import.parent_scope,
+                Some(finalize),
+                ignore_binding,
+                None,
+            ) {
                 let res = module.res().map(|r| (r, ident));
                 for error in &mut self.privacy_errors[privacy_errors_len..] {
                     error.outermost_res = res;
@@ -1050,7 +1049,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let mut all_ns_err = true;
         self.per_ns(|this, ns| {
             if !type_ns_only || ns == TypeNS {
-                let orig_vis = import.vis.take();
                 let binding = this.resolve_ident_in_module(
                     module,
                     ident,
@@ -1058,8 +1056,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     &import.parent_scope,
                     Some(Finalize { report_private: false, ..finalize }),
                     target_bindings[ns].get(),
+                    Some(import),
                 );
-                import.vis.set(orig_vis);
 
                 match binding {
                     Ok(binding) => {
@@ -1122,6 +1120,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         &import.parent_scope,
                         Some(finalize),
                         None,
+                        None,
                     );
                     if binding.is_ok() {
                         all_ns_failed = false;
@@ -1232,7 +1231,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let mut crate_private_reexport = false;
         self.per_ns(|this, ns| {
             if let Ok(binding) = source_bindings[ns].get() {
-                if !binding.vis.is_at_least(import.expect_vis(), this.tcx) {
+                if !binding.vis.is_at_least(import.vis, this.tcx) {
                     reexport_error = Some((ns, binding));
                     if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
                         if binding_def_id.is_top_level_module() {
@@ -1369,6 +1368,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     None,
                     false,
                     target_bindings[ns].get(),
+                    None,
                 ) {
                     Ok(other_binding) => {
                         is_redundant = binding.res() == other_binding.res()
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index f844930ad26..a5bd2fdd8f3 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1388,6 +1388,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             finalize,
             Some(&self.ribs),
             None,
+            None,
         )
     }
 
@@ -2667,119 +2668,128 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         let mut function_type_rib = Rib::new(kind);
         let mut function_value_rib = Rib::new(kind);
         let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
-        let mut seen_bindings = FxHashMap::default();
-        // Store all seen lifetimes names from outer scopes.
-        let mut seen_lifetimes = FxHashSet::default();
-
-        // We also can't shadow bindings from associated parent items.
-        for ns in [ValueNS, TypeNS] {
-            for parent_rib in self.ribs[ns].iter().rev() {
-                seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));
-
-                // Break at mod level, to account for nested items which are
-                // allowed to shadow generic param names.
-                if matches!(parent_rib.kind, RibKind::Module(..)) {
-                    break;
-                }
-            }
-        }
 
-        // Forbid shadowing lifetime bindings
-        for rib in self.lifetime_ribs.iter().rev() {
-            seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
-            if let LifetimeRibKind::Item = rib.kind {
-                break;
+        // Only check for shadowed bindings if we're declaring new params.
+        if !params.is_empty() {
+            let mut seen_bindings = FxHashMap::default();
+            // Store all seen lifetimes names from outer scopes.
+            let mut seen_lifetimes = FxHashSet::default();
+
+            // We also can't shadow bindings from associated parent items.
+            for ns in [ValueNS, TypeNS] {
+                for parent_rib in self.ribs[ns].iter().rev() {
+                    seen_bindings
+                        .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));
+
+                    // Break at mod level, to account for nested items which are
+                    // allowed to shadow generic param names.
+                    if matches!(parent_rib.kind, RibKind::Module(..)) {
+                        break;
+                    }
+                }
             }
-        }
 
-        for param in params {
-            let ident = param.ident.normalize_to_macros_2_0();
-            debug!("with_generic_param_rib: {}", param.id);
-
-            if let GenericParamKind::Lifetime = param.kind
-                && let Some(&original) = seen_lifetimes.get(&ident)
-            {
-                diagnostics::signal_lifetime_shadowing(self.r.tcx.sess, original, param.ident);
-                // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_param(param.id, LifetimeRes::Error);
-                continue;
+            // Forbid shadowing lifetime bindings
+            for rib in self.lifetime_ribs.iter().rev() {
+                seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
+                if let LifetimeRibKind::Item = rib.kind {
+                    break;
+                }
             }
 
-            match seen_bindings.entry(ident) {
-                Entry::Occupied(entry) => {
-                    let span = *entry.get();
-                    let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
-                    self.report_error(param.ident.span, err);
-                    let rib = match param.kind {
-                        GenericParamKind::Lifetime => {
-                            // Record lifetime res, so lowering knows there is something fishy.
-                            self.record_lifetime_param(param.id, LifetimeRes::Error);
-                            continue;
-                        }
-                        GenericParamKind::Type { .. } => &mut function_type_rib,
-                        GenericParamKind::Const { .. } => &mut function_value_rib,
-                    };
+            for param in params {
+                let ident = param.ident.normalize_to_macros_2_0();
+                debug!("with_generic_param_rib: {}", param.id);
 
-                    // Taint the resolution in case of errors to prevent follow up errors in typeck
-                    self.r.record_partial_res(param.id, PartialRes::new(Res::Err));
-                    rib.bindings.insert(ident, Res::Err);
+                if let GenericParamKind::Lifetime = param.kind
+                    && let Some(&original) = seen_lifetimes.get(&ident)
+                {
+                    diagnostics::signal_lifetime_shadowing(self.r.tcx.sess, original, param.ident);
+                    // Record lifetime res, so lowering knows there is something fishy.
+                    self.record_lifetime_param(param.id, LifetimeRes::Error);
                     continue;
                 }
-                Entry::Vacant(entry) => {
-                    entry.insert(param.ident.span);
-                }
-            }
 
-            if param.ident.name == kw::UnderscoreLifetime {
-                self.r
-                    .dcx()
-                    .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
-                // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_param(param.id, LifetimeRes::Error);
-                continue;
-            }
+                match seen_bindings.entry(ident) {
+                    Entry::Occupied(entry) => {
+                        let span = *entry.get();
+                        let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
+                        self.report_error(param.ident.span, err);
+                        let rib = match param.kind {
+                            GenericParamKind::Lifetime => {
+                                // Record lifetime res, so lowering knows there is something fishy.
+                                self.record_lifetime_param(param.id, LifetimeRes::Error);
+                                continue;
+                            }
+                            GenericParamKind::Type { .. } => &mut function_type_rib,
+                            GenericParamKind::Const { .. } => &mut function_value_rib,
+                        };
 
-            if param.ident.name == kw::StaticLifetime {
-                self.r.dcx().emit_err(errors::StaticLifetimeIsReserved {
-                    span: param.ident.span,
-                    lifetime: param.ident,
-                });
-                // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_param(param.id, LifetimeRes::Error);
-                continue;
-            }
+                        // Taint the resolution in case of errors to prevent follow up errors in typeck
+                        self.r.record_partial_res(param.id, PartialRes::new(Res::Err));
+                        rib.bindings.insert(ident, Res::Err);
+                        continue;
+                    }
+                    Entry::Vacant(entry) => {
+                        entry.insert(param.ident.span);
+                    }
+                }
 
-            let def_id = self.r.local_def_id(param.id);
+                if param.ident.name == kw::UnderscoreLifetime {
+                    self.r
+                        .dcx()
+                        .emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
+                    // Record lifetime res, so lowering knows there is something fishy.
+                    self.record_lifetime_param(param.id, LifetimeRes::Error);
+                    continue;
+                }
 
-            // Plain insert (no renaming).
-            let (rib, def_kind) = match param.kind {
-                GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
-                GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
-                GenericParamKind::Lifetime => {
-                    let res = LifetimeRes::Param { param: def_id, binder };
-                    self.record_lifetime_param(param.id, res);
-                    function_lifetime_rib.bindings.insert(ident, (param.id, res));
+                if param.ident.name == kw::StaticLifetime {
+                    self.r.dcx().emit_err(errors::StaticLifetimeIsReserved {
+                        span: param.ident.span,
+                        lifetime: param.ident,
+                    });
+                    // Record lifetime res, so lowering knows there is something fishy.
+                    self.record_lifetime_param(param.id, LifetimeRes::Error);
                     continue;
                 }
-            };
 
-            let res = match kind {
-                RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()),
-                RibKind::Normal => {
-                    // FIXME(non_lifetime_binders): Stop special-casing
-                    // const params to error out here.
-                    if self.r.tcx.features().non_lifetime_binders
-                        && matches!(param.kind, GenericParamKind::Type { .. })
-                    {
+                let def_id = self.r.local_def_id(param.id);
+
+                // Plain insert (no renaming).
+                let (rib, def_kind) = match param.kind {
+                    GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
+                    GenericParamKind::Const { .. } => {
+                        (&mut function_value_rib, DefKind::ConstParam)
+                    }
+                    GenericParamKind::Lifetime => {
+                        let res = LifetimeRes::Param { param: def_id, binder };
+                        self.record_lifetime_param(param.id, res);
+                        function_lifetime_rib.bindings.insert(ident, (param.id, res));
+                        continue;
+                    }
+                };
+
+                let res = match kind {
+                    RibKind::Item(..) | RibKind::AssocItem => {
                         Res::Def(def_kind, def_id.to_def_id())
-                    } else {
-                        Res::Err
                     }
-                }
-                _ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
-            };
-            self.r.record_partial_res(param.id, PartialRes::new(res));
-            rib.bindings.insert(ident, res);
+                    RibKind::Normal => {
+                        // FIXME(non_lifetime_binders): Stop special-casing
+                        // const params to error out here.
+                        if self.r.tcx.features().non_lifetime_binders
+                            && matches!(param.kind, GenericParamKind::Type { .. })
+                        {
+                            Res::Def(def_kind, def_id.to_def_id())
+                        } else {
+                            Res::Err
+                        }
+                    }
+                    _ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
+                };
+                self.r.record_partial_res(param.id, PartialRes::new(res));
+                rib.bindings.insert(ident, res);
+            }
         }
 
         self.lifetime_ribs.push(function_lifetime_rib);
@@ -4186,7 +4196,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
             let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
             if let Ok((_, res)) =
-                self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false)
+                self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
             {
                 return Ok(Some(PartialRes::new(res)));
             }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index f126563fe58..f9896fb2196 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2058,6 +2058,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 ident,
                 ns,
                 &self.parent_scope,
+                None,
             ) {
                 let res = binding.res();
                 if filter_fn(res) {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 79d3bb685b3..89ac839651f 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1129,9 +1129,6 @@ pub struct Resolver<'a, 'tcx> {
     /// Also includes of list of each fields visibility
     struct_constructors: LocalDefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>,
 
-    /// Features declared for this crate.
-    declared_features: FxHashSet<Symbol>,
-
     lint_buffer: LintBuffer,
 
     next_node_id: NodeId,
@@ -1402,7 +1399,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         let registered_tools = tcx.registered_tools(());
 
-        let features = tcx.features();
         let pub_vis = ty::Visibility::<DefId>::Public;
         let edition = tcx.sess.edition();
 
@@ -1506,7 +1502,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             multi_segment_macro_resolutions: Default::default(),
             builtin_attrs: Default::default(),
             containers_deriving_copy: Default::default(),
-            declared_features: features.declared_features.clone(),
             lint_buffer: LintBuffer::default(),
             next_node_id: CRATE_NODE_ID,
             node_id_to_def_id,
@@ -2120,7 +2115,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
         }
 
-        match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
+        match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
             PathResult::NonModule(path_res) => path_res.full_res(),
             PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
@@ -2204,6 +2199,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ident,
             ValueNS,
             parent_scope,
+            None,
         ) else {
             return;
         };
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 64ae0d82952..da7278175e9 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -39,6 +39,7 @@ use crate::errors::{
     self, AddAsNonDerive, CannotDetermineMacroResolution, CannotFindIdentInThisScope,
     MacroExpectedFound, RemoveSurroundingDerive,
 };
+use crate::imports::Import;
 use crate::Namespace::*;
 use crate::{
     BindingKey, BuiltinMacroState, DeriveData, Determinacy, Finalize, MacroData, ModuleKind,
@@ -399,6 +400,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
                         &parent_scope,
                         true,
                         force,
+                        None,
                     ) {
                         Ok((Some(ext), _)) => {
                             if !ext.helper_attrs.is_empty() {
@@ -551,6 +553,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             force,
             deleg_impl,
             invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
+            None,
         ) {
             Ok((Some(ext), res)) => (ext, res),
             Ok((None, res)) => (self.dummy_ext(kind), res),
@@ -704,8 +707,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         parent_scope: &ParentScope<'a>,
         trace: bool,
         force: bool,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
-        self.resolve_macro_or_delegation_path(path, kind, parent_scope, trace, force, None, None)
+        self.resolve_macro_or_delegation_path(
+            path,
+            kind,
+            parent_scope,
+            trace,
+            force,
+            None,
+            None,
+            ignore_import,
+        )
     }
 
     fn resolve_macro_or_delegation_path(
@@ -717,6 +730,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         force: bool,
         deleg_impl: Option<LocalDefId>,
         invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
+        ignore_import: Option<Import<'a>>,
     ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
         let path_span = ast_path.span;
         let mut path = Segment::from_path(ast_path);
@@ -733,7 +747,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         let res = if deleg_impl.is_some() || path.len() > 1 {
             let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS };
-            let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope) {
+            let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) {
                 PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
                 PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
                 PathResult::NonModule(..)
@@ -768,6 +782,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 None,
                 force,
                 None,
+                None,
             );
             if let Err(Determinacy::Undetermined) = binding {
                 return Err(Determinacy::Undetermined);
@@ -852,6 +867,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 &parent_scope,
                 Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
                 None,
+                None,
             ) {
                 PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
                     check_consistency(self, &path, path_span, kind, initial_res, res)
@@ -871,7 +887,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         if let PathResult::Failed { span, label, module, .. } = path_res {
                             // try to suggest if it's not a macro, maybe a function
                             if let PathResult::NonModule(partial_res) =
-                                self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
+                                self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None)
                                 && partial_res.unresolved_segments() == 0
                             {
                                 let sm = self.tcx.sess.source_map();
@@ -921,6 +937,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
                 None,
+                None,
             ) {
                 Ok(binding) => {
                     let initial_res = initial_binding.map(|initial_binding| {
@@ -966,6 +983,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
                 None,
+                None,
             );
         }
     }
@@ -983,7 +1001,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let feature = stability.feature;
 
                 let is_allowed = |feature| {
-                    self.declared_features.contains(&feature) || span.allows_unstable(feature)
+                    self.tcx.features().declared_features.contains(&feature)
+                        || span.allows_unstable(feature)
                 };
                 let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
                 if !is_allowed(feature) && !allowed_by_implication {
@@ -1070,6 +1089,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 None,
                 false,
                 None,
+                None,
             );
             if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) {
                 self.tcx.sess.psess.buffer_lint(
@@ -1143,7 +1163,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         let mut indeterminate = false;
         for ns in namespaces {
-            match self.maybe_resolve_path(path, Some(*ns), &parent_scope) {
+            match self.maybe_resolve_path(path, Some(*ns), &parent_scope, None) {
                 PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true),
                 PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
                     return Ok(true);
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
index ac664c53f44..cb15c67b895 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
@@ -6,7 +6,7 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::bug;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_target::abi::call::{Conv, FnAbi, PassMode};
 use tracing::instrument;
 
@@ -112,11 +112,12 @@ pub fn typeid_for_instance<'tcx>(
     instance: Instance<'tcx>,
     options: TypeIdOptions,
 ) -> String {
+    assert!(!instance.has_non_region_param(), "{instance:#?} must be fully monomorphic");
     let transform_ty_options = TransformTyOptions::from_bits(options.bits())
         .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits()));
     let instance = transform_instance(tcx, instance, transform_ty_options);
     let fn_abi = tcx
-        .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
+        .fn_abi_of_instance(ty::ParamEnv::reveal_all().and((instance, ty::List::empty())))
         .unwrap_or_else(|error| {
             bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
         });
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index f58a991a616..95d171409d8 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -602,7 +602,7 @@ impl OutputType {
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum ErrorOutputType {
     /// Output meant for the consumption of humans.
-    HumanReadable(HumanReadableErrorType),
+    HumanReadable(HumanReadableErrorType, ColorConfig),
     /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
     Json {
         /// Render the JSON in a human readable way (with indents and newlines).
@@ -610,12 +610,13 @@ pub enum ErrorOutputType {
         /// The JSON output includes a `rendered` field that includes the rendered
         /// human output.
         json_rendered: HumanReadableErrorType,
+        color_config: ColorConfig,
     },
 }
 
 impl Default for ErrorOutputType {
     fn default() -> Self {
-        Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
+        Self::HumanReadable(HumanReadableErrorType::Default, ColorConfig::Auto)
     }
 }
 
@@ -838,10 +839,14 @@ pub enum Input {
 
 impl Input {
     pub fn filestem(&self) -> &str {
-        match *self {
-            Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
-            Input::Str { .. } => "rust_out",
+        if let Input::File(ifile) = self {
+            // If for some reason getting the file stem as a UTF-8 string fails,
+            // then fallback to a fixed name.
+            if let Some(name) = ifile.file_stem().and_then(OsStr::to_str) {
+                return name;
+            }
         }
+        "rust_out"
     }
 
     pub fn source_name(&self) -> FileName {
@@ -1300,7 +1305,10 @@ pub(crate) const fn default_lib_output() -> CrateType {
 }
 
 pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
-    // Combine the configuration requested by the session (command line) with
+    // First disallow some configuration given on the command line
+    cfg::disallow_cfgs(sess, &user_cfg);
+
+    // Then combine the configuration requested by the session (command line) with
     // some default and generated configuration items.
     user_cfg.extend(cfg::default_configuration(sess));
     user_cfg
@@ -1624,6 +1632,7 @@ pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Col
 /// Possible json config files
 pub struct JsonConfig {
     pub json_rendered: HumanReadableErrorType,
+    pub json_color: ColorConfig,
     json_artifact_notifications: bool,
     pub json_unused_externs: JsonUnusedExterns,
     json_future_incompat: bool,
@@ -1661,8 +1670,7 @@ impl JsonUnusedExterns {
 /// The first value returned is how to render JSON diagnostics, and the second
 /// is whether or not artifact notifications are enabled.
 pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
-    let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
-        HumanReadableErrorType::Default;
+    let mut json_rendered = HumanReadableErrorType::Default;
     let mut json_color = ColorConfig::Never;
     let mut json_artifact_notifications = false;
     let mut json_unused_externs = JsonUnusedExterns::No;
@@ -1689,7 +1697,8 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json
     }
 
     JsonConfig {
-        json_rendered: json_rendered(json_color),
+        json_rendered,
+        json_color,
         json_artifact_notifications,
         json_unused_externs,
         json_future_incompat,
@@ -1701,6 +1710,7 @@ pub fn parse_error_format(
     early_dcx: &mut EarlyDiagCtxt,
     matches: &getopts::Matches,
     color: ColorConfig,
+    json_color: ColorConfig,
     json_rendered: HumanReadableErrorType,
 ) -> ErrorOutputType {
     // We need the `opts_present` check because the driver will send us Matches
@@ -1710,18 +1720,22 @@ pub fn parse_error_format(
     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
         match matches.opt_str("error-format").as_deref() {
             None | Some("human") => {
-                ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
+                ErrorOutputType::HumanReadable(HumanReadableErrorType::Default, color)
             }
             Some("human-annotate-rs") => {
-                ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
+                ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, color)
             }
-            Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
-            Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
-            Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
-
+            Some("json") => {
+                ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color }
+            }
+            Some("pretty-json") => {
+                ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
+            }
+            Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short, color),
             Some(arg) => {
                 early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
-                    HumanReadableErrorType::Default(color),
+                    HumanReadableErrorType::Default,
+                    color,
                 ));
                 early_dcx.early_fatal(format!(
                     "argument for `--error-format` must be `human`, `json` or \
@@ -1730,7 +1744,7 @@ pub fn parse_error_format(
             }
         }
     } else {
-        ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
+        ErrorOutputType::HumanReadable(HumanReadableErrorType::Default, color)
     };
 
     match error_format {
@@ -1784,7 +1798,7 @@ fn check_error_format_stability(
         if let ErrorOutputType::Json { pretty: true, .. } = error_format {
             early_dcx.early_fatal("`--error-format=pretty-json` is unstable");
         }
-        if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
+        if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, _) =
             error_format
         {
             early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable");
@@ -2385,12 +2399,13 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
 
     let JsonConfig {
         json_rendered,
+        json_color,
         json_artifact_notifications,
         json_unused_externs,
         json_future_incompat,
     } = parse_json(early_dcx, matches);
 
-    let error_format = parse_error_format(early_dcx, matches, color, json_rendered);
+    let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
 
     early_dcx.abort_if_error_and_set_error_format(error_format);
 
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index 4109ebb6d34..a64b1e21e9e 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -17,12 +17,16 @@
 //!  - Add the activation logic in [`default_configuration`]
 //!  - Add the cfg to [`CheckCfg::fill_well_known`] (and related files),
 //!    so that the compiler can know the cfg is expected
+//!  - Add the cfg in [`disallow_cfgs`] to disallow users from setting it via `--cfg`
 //!  - Add the feature gating in `compiler/rustc_feature/src/builtin_attrs.rs`
 
 use std::hash::Hash;
 use std::iter;
 
+use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::Align;
 use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, Target, TargetTriple, TARGETS};
@@ -82,6 +86,67 @@ impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
     }
 }
 
+/// Disallow builtin cfgs from the CLI.
+pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
+    let disallow = |cfg: &(Symbol, Option<Symbol>), controlled_by| {
+        let cfg_name = cfg.0;
+        let cfg = if let Some(value) = cfg.1 {
+            format!(r#"{}="{}""#, cfg_name, value)
+        } else {
+            format!("{}", cfg_name)
+        };
+        sess.psess.opt_span_buffer_lint(
+            EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
+            None,
+            ast::CRATE_NODE_ID,
+            BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by },
+        )
+    };
+
+    // We want to restrict setting builtin cfgs that will produce incoherent behavior
+    // between the cfg and the rustc cli flag that sets it.
+    //
+    // The tests are in tests/ui/cfg/disallowed-cli-cfgs.rs.
+
+    // By-default all builtin cfgs are disallowed, only those are allowed:
+    //  - test: as it makes sense to the have the `test` cfg active without the builtin
+    //          test harness. See Cargo `harness = false` config.
+    //
+    // Cargo `--cfg test`: https://github.com/rust-lang/cargo/blob/bc89bffa5987d4af8f71011c7557119b39e44a65/src/cargo/core/compiler/mod.rs#L1124
+
+    for cfg in user_cfgs {
+        match cfg {
+            (sym::overflow_checks, None) => disallow(cfg, "-C overflow-checks"),
+            (sym::debug_assertions, None) => disallow(cfg, "-C debug-assertions"),
+            (sym::ub_checks, None) => disallow(cfg, "-Z ub-checks"),
+            (sym::sanitize, None | Some(_)) => disallow(cfg, "-Z sanitizer"),
+            (
+                sym::sanitizer_cfi_generalize_pointers | sym::sanitizer_cfi_normalize_integers,
+                None | Some(_),
+            ) => disallow(cfg, "-Z sanitizer=cfi"),
+            (sym::proc_macro, None) => disallow(cfg, "--crate-type proc-macro"),
+            (sym::panic, Some(sym::abort | sym::unwind)) => disallow(cfg, "-C panic"),
+            (sym::target_feature, Some(_)) => disallow(cfg, "-C target-feature"),
+            (sym::unix, None)
+            | (sym::windows, None)
+            | (sym::relocation_model, Some(_))
+            | (sym::target_abi, None | Some(_))
+            | (sym::target_arch, Some(_))
+            | (sym::target_endian, Some(_))
+            | (sym::target_env, None | Some(_))
+            | (sym::target_family, Some(_))
+            | (sym::target_os, Some(_))
+            | (sym::target_pointer_width, Some(_))
+            | (sym::target_vendor, None | Some(_))
+            | (sym::target_has_atomic, Some(_))
+            | (sym::target_has_atomic_equal_alignment, Some(_))
+            | (sym::target_has_atomic_load_store, Some(_))
+            | (sym::target_thread_local, None) => disallow(cfg, "--target"),
+            _ => {}
+        }
+    }
+}
+
 /// Generate the default configs for a given session
 pub(crate) fn default_configuration(sess: &Session) -> Cfg {
     let mut ret = Cfg::default();
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 0c3ec36fed5..63ca5fefd9f 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -19,6 +19,11 @@ pub struct FileSearch<'a> {
 }
 
 impl<'a> FileSearch<'a> {
+    pub fn cli_search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
+        let kind = self.kind;
+        self.cli_search_paths.iter().filter(move |sp| sp.kind.matches(kind))
+    }
+
     pub fn search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
         let kind = self.kind;
         self.cli_search_paths
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index bf54aae1cfe..4b87f5d62b2 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1827,6 +1827,8 @@ options! {
         the same values as the target option of the same name"),
     meta_stats: bool = (false, parse_bool, [UNTRACKED],
         "gather metadata statistics (default: no)"),
+    metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+        "stores metrics about the errors being emitted by rustc to disk"),
     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index ebd5021dae1..d6c58e9d1be 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -307,9 +307,19 @@ impl ParseSess {
         node_id: NodeId,
         diagnostic: BuiltinLintDiag,
     ) {
+        self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic)
+    }
+
+    pub fn opt_span_buffer_lint(
+        &self,
+        lint: &'static Lint,
+        span: Option<MultiSpan>,
+        node_id: NodeId,
+        diagnostic: BuiltinLintDiag,
+    ) {
         self.buffered_lints.with_lock(|buffered_lints| {
             buffered_lints.push(BufferedEarlyLint {
-                span: span.into(),
+                span,
                 node_id,
                 lint_id: LintId::of(lint),
                 diagnostic,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index be67baf57f6..672dddf871e 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -950,10 +950,10 @@ fn default_emitter(
         t => t,
     };
     match sopts.error_format {
-        config::ErrorOutputType::HumanReadable(kind) => {
-            let (short, color_config) = kind.unzip();
+        config::ErrorOutputType::HumanReadable(kind, color_config) => {
+            let short = kind.short();
 
-            if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
+            if let HumanReadableErrorType::AnnotateSnippet = kind {
                 let emitter = AnnotateSnippetEmitter::new(
                     Some(source_map),
                     bundle,
@@ -978,13 +978,14 @@ fn default_emitter(
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             }
         }
-        config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(
+        config::ErrorOutputType::Json { pretty, json_rendered, color_config } => Box::new(
             JsonEmitter::new(
                 Box::new(io::BufWriter::new(io::stderr())),
                 source_map,
                 fallback_bundle,
                 pretty,
                 json_rendered,
+                color_config,
             )
             .registry(Some(registry))
             .fluent_bundle(bundle)
@@ -1425,20 +1426,23 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
     let fallback_bundle =
         fallback_fluent_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false);
     let emitter: Box<DynEmitter> = match output {
-        config::ErrorOutputType::HumanReadable(kind) => {
-            let (short, color_config) = kind.unzip();
+        config::ErrorOutputType::HumanReadable(kind, color_config) => {
+            let short = kind.short();
             Box::new(
                 HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
                     .short_message(short),
             )
         }
-        config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::new(
-            Box::new(io::BufWriter::new(io::stderr())),
-            Lrc::new(SourceMap::new(FilePathMapping::empty())),
-            fallback_bundle,
-            pretty,
-            json_rendered,
-        )),
+        config::ErrorOutputType::Json { pretty, json_rendered, color_config } => {
+            Box::new(JsonEmitter::new(
+                Box::new(io::BufWriter::new(io::stderr())),
+                Lrc::new(SourceMap::new(FilePathMapping::empty())),
+                fallback_bundle,
+                pretty,
+                json_rendered,
+                color_config,
+            ))
+        }
     };
     emitter
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e8563f50158..32fca6733bb 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -276,6 +276,7 @@ symbols! {
         Path,
         PathBuf,
         Pending,
+        PinCoerceUnsized,
         Pointer,
         Poll,
         ProcMacro,
@@ -1216,6 +1217,7 @@ symbols! {
         mir_static_mut,
         mir_storage_dead,
         mir_storage_live,
+        mir_tail_call,
         mir_unreachable,
         mir_unwind_cleanup,
         mir_unwind_continue,
@@ -1705,6 +1707,7 @@ symbols! {
         self_in_typedefs,
         self_struct_ctor,
         semitransparent,
+        sha512_sm_x86,
         shadow_call_stack,
         shl,
         shl_assign,
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index ecc91ab9a31..b2116c51216 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -9,12 +9,12 @@
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
-#![feature(min_exhaustive_patterns)]
 #![feature(rustc_attrs)]
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
index 3e575fdd528..8b401329868 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs
@@ -21,6 +21,7 @@ pub fn target() -> Target {
             llvm_abiname: "lp64d".into(),
             max_atomic_width: Some(64),
             supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
+            crt_static_default: false,
             ..base::linux_musl::opts()
         },
     }
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 532507cb182..da66ba270b3 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_span::symbol::{sym, Symbol};
 
 /// Features that control behaviour of rustc, rather than the codegen.
@@ -53,136 +54,154 @@ impl Stability {
 //
 // Stabilizing a target feature requires t-lang approval.
 
-const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+type ImpliedFeatures = &'static [&'static str];
+
+const ARM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("aclass", Unstable(sym::arm_target_feature)),
-    ("aes", Unstable(sym::arm_target_feature)),
-    ("crc", Unstable(sym::arm_target_feature)),
-    ("d32", Unstable(sym::arm_target_feature)),
-    ("dotprod", Unstable(sym::arm_target_feature)),
-    ("dsp", Unstable(sym::arm_target_feature)),
-    ("fp-armv8", Unstable(sym::arm_target_feature)),
-    ("i8mm", Unstable(sym::arm_target_feature)),
-    ("mclass", Unstable(sym::arm_target_feature)),
-    ("neon", Unstable(sym::arm_target_feature)),
-    ("rclass", Unstable(sym::arm_target_feature)),
-    ("sha2", Unstable(sym::arm_target_feature)),
+    ("aclass", Unstable(sym::arm_target_feature), &[]),
+    ("aes", Unstable(sym::arm_target_feature), &["neon"]),
+    ("crc", Unstable(sym::arm_target_feature), &[]),
+    ("d32", Unstable(sym::arm_target_feature), &[]),
+    ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
+    ("dsp", Unstable(sym::arm_target_feature), &[]),
+    ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
+    ("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
+    ("mclass", Unstable(sym::arm_target_feature), &[]),
+    ("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
+    ("rclass", Unstable(sym::arm_target_feature), &[]),
+    ("sha2", Unstable(sym::arm_target_feature), &["neon"]),
     // This is needed for inline assembly, but shouldn't be stabilized as-is
     // since it should be enabled per-function using #[instruction_set], not
     // #[target_feature].
-    ("thumb-mode", Unstable(sym::arm_target_feature)),
-    ("thumb2", Unstable(sym::arm_target_feature)),
-    ("trustzone", Unstable(sym::arm_target_feature)),
-    ("v5te", Unstable(sym::arm_target_feature)),
-    ("v6", Unstable(sym::arm_target_feature)),
-    ("v6k", Unstable(sym::arm_target_feature)),
-    ("v6t2", Unstable(sym::arm_target_feature)),
-    ("v7", Unstable(sym::arm_target_feature)),
-    ("v8", Unstable(sym::arm_target_feature)),
-    ("vfp2", Unstable(sym::arm_target_feature)),
-    ("vfp3", Unstable(sym::arm_target_feature)),
-    ("vfp4", Unstable(sym::arm_target_feature)),
-    ("virtualization", Unstable(sym::arm_target_feature)),
+    ("thumb-mode", Unstable(sym::arm_target_feature), &[]),
+    ("thumb2", Unstable(sym::arm_target_feature), &[]),
+    ("trustzone", Unstable(sym::arm_target_feature), &[]),
+    ("v5te", Unstable(sym::arm_target_feature), &[]),
+    ("v6", Unstable(sym::arm_target_feature), &["v5te"]),
+    ("v6k", Unstable(sym::arm_target_feature), &["v6"]),
+    ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]),
+    ("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
+    ("v8", Unstable(sym::arm_target_feature), &["v7"]),
+    ("vfp2", Unstable(sym::arm_target_feature), &[]),
+    ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]),
+    ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
+    ("virtualization", Unstable(sym::arm_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     // FEAT_AES & FEAT_PMULL
-    ("aes", Stable),
+    ("aes", Stable, &["neon"]),
     // FEAT_BF16
-    ("bf16", Stable),
+    ("bf16", Stable, &[]),
     // FEAT_BTI
-    ("bti", Stable),
+    ("bti", Stable, &[]),
     // FEAT_CRC
-    ("crc", Stable),
+    ("crc", Stable, &[]),
     // FEAT_DIT
-    ("dit", Stable),
+    ("dit", Stable, &[]),
     // FEAT_DotProd
-    ("dotprod", Stable),
+    ("dotprod", Stable, &["neon"]),
     // FEAT_DPB
-    ("dpb", Stable),
+    ("dpb", Stable, &[]),
     // FEAT_DPB2
-    ("dpb2", Stable),
+    ("dpb2", Stable, &["dpb"]),
     // FEAT_F32MM
-    ("f32mm", Stable),
+    ("f32mm", Stable, &["sve"]),
     // FEAT_F64MM
-    ("f64mm", Stable),
+    ("f64mm", Stable, &["sve"]),
     // FEAT_FCMA
-    ("fcma", Stable),
+    ("fcma", Stable, &["neon"]),
     // FEAT_FHM
-    ("fhm", Stable),
+    ("fhm", Stable, &["fp16"]),
     // FEAT_FLAGM
-    ("flagm", Stable),
+    ("flagm", Stable, &[]),
     // FEAT_FP16
-    ("fp16", Stable),
+    // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
+    ("fp16", Stable, &["neon"]),
     // FEAT_FRINTTS
-    ("frintts", Stable),
+    ("frintts", Stable, &[]),
     // FEAT_I8MM
-    ("i8mm", Stable),
+    ("i8mm", Stable, &[]),
     // FEAT_JSCVT
-    ("jsconv", Stable),
+    // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
+    ("jsconv", Stable, &["neon"]),
     // FEAT_LOR
-    ("lor", Stable),
+    ("lor", Stable, &[]),
     // FEAT_LSE
-    ("lse", Stable),
+    ("lse", Stable, &[]),
     // FEAT_MTE & FEAT_MTE2
-    ("mte", Stable),
+    ("mte", Stable, &[]),
     // FEAT_AdvSimd & FEAT_FP
-    ("neon", Stable),
+    ("neon", Stable, &[]),
     // FEAT_PAUTH (address authentication)
-    ("paca", Stable),
+    ("paca", Stable, &[]),
     // FEAT_PAUTH (generic authentication)
-    ("pacg", Stable),
+    ("pacg", Stable, &[]),
     // FEAT_PAN
-    ("pan", Stable),
+    ("pan", Stable, &[]),
     // FEAT_PMUv3
-    ("pmuv3", Stable),
+    ("pmuv3", Stable, &[]),
     // FEAT_RAND
-    ("rand", Stable),
+    ("rand", Stable, &[]),
     // FEAT_RAS & FEAT_RASv1p1
-    ("ras", Stable),
+    ("ras", Stable, &[]),
     // FEAT_RCPC
-    ("rcpc", Stable),
+    ("rcpc", Stable, &[]),
     // FEAT_RCPC2
-    ("rcpc2", Stable),
+    ("rcpc2", Stable, &["rcpc"]),
     // FEAT_RDM
-    ("rdm", Stable),
+    ("rdm", Stable, &["neon"]),
     // FEAT_SB
-    ("sb", Stable),
+    ("sb", Stable, &[]),
     // FEAT_SHA1 & FEAT_SHA256
-    ("sha2", Stable),
+    ("sha2", Stable, &["neon"]),
     // FEAT_SHA512 & FEAT_SHA3
-    ("sha3", Stable),
+    ("sha3", Stable, &["sha2"]),
     // FEAT_SM3 & FEAT_SM4
-    ("sm4", Stable),
+    ("sm4", Stable, &["neon"]),
     // FEAT_SPE
-    ("spe", Stable),
+    ("spe", Stable, &[]),
     // FEAT_SSBS & FEAT_SSBS2
-    ("ssbs", Stable),
+    ("ssbs", Stable, &[]),
     // FEAT_SVE
-    ("sve", Stable),
+    // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608
+    //
+    // LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always
+    // exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2
+    //
+    // "For backwards compatibility, Neon and VFP are required in the latest architectures."
+    ("sve", Stable, &["neon"]),
     // FEAT_SVE2
-    ("sve2", Stable),
+    ("sve2", Stable, &["sve"]),
     // FEAT_SVE2_AES
-    ("sve2-aes", Stable),
+    ("sve2-aes", Stable, &["sve2", "aes"]),
     // FEAT_SVE2_BitPerm
-    ("sve2-bitperm", Stable),
+    ("sve2-bitperm", Stable, &["sve2"]),
     // FEAT_SVE2_SHA3
-    ("sve2-sha3", Stable),
+    ("sve2-sha3", Stable, &["sve2", "sha3"]),
     // FEAT_SVE2_SM4
-    ("sve2-sm4", Stable),
+    ("sve2-sm4", Stable, &["sve2", "sm4"]),
     // FEAT_TME
-    ("tme", Stable),
-    ("v8.1a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.2a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.3a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.4a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.5a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.6a", Unstable(sym::aarch64_ver_target_feature)),
-    ("v8.7a", Unstable(sym::aarch64_ver_target_feature)),
+    ("tme", Stable, &[]),
+    (
+        "v8.1a",
+        Unstable(sym::aarch64_ver_target_feature),
+        &["crc", "lse", "rdm", "pan", "lor", "vh"],
+    ),
+    ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
+    (
+        "v8.3a",
+        Unstable(sym::aarch64_ver_target_feature),
+        &["v8.2a", "rcpc", "paca", "pacg", "jsconv"],
+    ),
+    ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]),
+    ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
+    ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]),
+    ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &[]),
     // FEAT_VHE
-    ("vh", Stable),
+    ("vh", Stable, &[]),
     // tidy-alphabetical-end
 ];
 
@@ -190,219 +209,223 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
     &["paca", "pacg"], // Together these represent `pauth` in LLVM
 ];
 
-const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("adx", Stable),
-    ("aes", Stable),
-    ("amx-bf16", Unstable(sym::x86_amx_intrinsics)),
-    ("amx-complex", Unstable(sym::x86_amx_intrinsics)),
-    ("amx-fp16", Unstable(sym::x86_amx_intrinsics)),
-    ("amx-int8", Unstable(sym::x86_amx_intrinsics)),
-    ("amx-tile", Unstable(sym::x86_amx_intrinsics)),
-    ("avx", Stable),
-    ("avx2", Stable),
-    ("avx512bf16", Unstable(sym::avx512_target_feature)),
-    ("avx512bitalg", Unstable(sym::avx512_target_feature)),
-    ("avx512bw", Unstable(sym::avx512_target_feature)),
-    ("avx512cd", Unstable(sym::avx512_target_feature)),
-    ("avx512dq", Unstable(sym::avx512_target_feature)),
-    ("avx512f", Unstable(sym::avx512_target_feature)),
-    ("avx512fp16", Unstable(sym::avx512_target_feature)),
-    ("avx512ifma", Unstable(sym::avx512_target_feature)),
-    ("avx512vbmi", Unstable(sym::avx512_target_feature)),
-    ("avx512vbmi2", Unstable(sym::avx512_target_feature)),
-    ("avx512vl", Unstable(sym::avx512_target_feature)),
-    ("avx512vnni", Unstable(sym::avx512_target_feature)),
-    ("avx512vp2intersect", Unstable(sym::avx512_target_feature)),
-    ("avx512vpopcntdq", Unstable(sym::avx512_target_feature)),
-    ("avxifma", Unstable(sym::avx512_target_feature)),
-    ("avxneconvert", Unstable(sym::avx512_target_feature)),
-    ("avxvnni", Unstable(sym::avx512_target_feature)),
-    ("avxvnniint16", Unstable(sym::avx512_target_feature)),
-    ("avxvnniint8", Unstable(sym::avx512_target_feature)),
-    ("bmi1", Stable),
-    ("bmi2", Stable),
-    ("cmpxchg16b", Stable),
-    ("ermsb", Unstable(sym::ermsb_target_feature)),
-    ("f16c", Stable),
-    ("fma", Stable),
-    ("fxsr", Stable),
-    ("gfni", Unstable(sym::avx512_target_feature)),
-    ("lahfsahf", Unstable(sym::lahfsahf_target_feature)),
-    ("lzcnt", Stable),
-    ("movbe", Stable),
-    ("pclmulqdq", Stable),
-    ("popcnt", Stable),
-    ("prfchw", Unstable(sym::prfchw_target_feature)),
-    ("rdrand", Stable),
-    ("rdseed", Stable),
-    ("rtm", Unstable(sym::rtm_target_feature)),
-    ("sha", Stable),
-    ("sse", Stable),
-    ("sse2", Stable),
-    ("sse3", Stable),
-    ("sse4.1", Stable),
-    ("sse4.2", Stable),
-    ("sse4a", Unstable(sym::sse4a_target_feature)),
-    ("ssse3", Stable),
-    ("tbm", Unstable(sym::tbm_target_feature)),
-    ("vaes", Unstable(sym::avx512_target_feature)),
-    ("vpclmulqdq", Unstable(sym::avx512_target_feature)),
-    ("xop", Unstable(sym::xop_target_feature)),
-    ("xsave", Stable),
-    ("xsavec", Stable),
-    ("xsaveopt", Stable),
-    ("xsaves", Stable),
+    ("adx", Stable, &[]),
+    ("aes", Stable, &["sse2"]),
+    ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
+    ("avx", Stable, &["sse4.2"]),
+    ("avx2", Stable, &["avx"]),
+    ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
+    ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]),
+    ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("bmi1", Stable, &[]),
+    ("bmi2", Stable, &[]),
+    ("cmpxchg16b", Stable, &[]),
+    ("ermsb", Unstable(sym::ermsb_target_feature), &[]),
+    ("f16c", Stable, &["avx"]),
+    ("fma", Stable, &["avx"]),
+    ("fxsr", Stable, &[]),
+    ("gfni", Unstable(sym::avx512_target_feature), &["sse2"]),
+    ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
+    ("lzcnt", Stable, &[]),
+    ("movbe", Stable, &[]),
+    ("pclmulqdq", Stable, &[]),
+    ("popcnt", Stable, &[]),
+    ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
+    ("rdrand", Stable, &[]),
+    ("rdseed", Stable, &[]),
+    ("rtm", Unstable(sym::rtm_target_feature), &[]),
+    ("sha", Stable, &["sse2"]),
+    ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
+    ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
+    ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
+    ("sse", Stable, &[]),
+    ("sse2", Stable, &["sse"]),
+    ("sse3", Stable, &["sse2"]),
+    ("sse4.1", Stable, &["ssse3"]),
+    ("sse4.2", Stable, &["sse4.1"]),
+    ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
+    ("ssse3", Stable, &["sse3"]),
+    ("tbm", Unstable(sym::tbm_target_feature), &[]),
+    ("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]),
+    ("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
+    ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
+    ("xsave", Stable, &[]),
+    ("xsavec", Stable, &["xsave"]),
+    ("xsaveopt", Stable, &["xsave"]),
+    ("xsaves", Stable, &["xsave"]),
     // tidy-alphabetical-end
 ];
 
-const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("hvx", Unstable(sym::hexagon_target_feature)),
-    ("hvx-length128b", Unstable(sym::hexagon_target_feature)),
+    ("hvx", Unstable(sym::hexagon_target_feature), &[]),
+    ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
     // tidy-alphabetical-end
 ];
 
-const POWERPC_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("altivec", Unstable(sym::powerpc_target_feature)),
-    ("power10-vector", Unstable(sym::powerpc_target_feature)),
-    ("power8-altivec", Unstable(sym::powerpc_target_feature)),
-    ("power8-vector", Unstable(sym::powerpc_target_feature)),
-    ("power9-altivec", Unstable(sym::powerpc_target_feature)),
-    ("power9-vector", Unstable(sym::powerpc_target_feature)),
-    ("vsx", Unstable(sym::powerpc_target_feature)),
+    ("altivec", Unstable(sym::powerpc_target_feature), &[]),
+    ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
+    ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
+    ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
+    ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
+    ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
+    ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
     // tidy-alphabetical-end
 ];
 
-const MIPS_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("fp64", Unstable(sym::mips_target_feature)),
-    ("msa", Unstable(sym::mips_target_feature)),
-    ("virt", Unstable(sym::mips_target_feature)),
+    ("fp64", Unstable(sym::mips_target_feature), &[]),
+    ("msa", Unstable(sym::mips_target_feature), &[]),
+    ("virt", Unstable(sym::mips_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("a", Stable),
-    ("c", Stable),
-    ("d", Unstable(sym::riscv_target_feature)),
-    ("e", Unstable(sym::riscv_target_feature)),
-    ("f", Unstable(sym::riscv_target_feature)),
-    ("m", Stable),
-    ("relax", Unstable(sym::riscv_target_feature)),
-    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature)),
-    ("v", Unstable(sym::riscv_target_feature)),
-    ("zba", Stable),
-    ("zbb", Stable),
-    ("zbc", Stable),
-    ("zbkb", Stable),
-    ("zbkc", Stable),
-    ("zbkx", Stable),
-    ("zbs", Stable),
-    ("zdinx", Unstable(sym::riscv_target_feature)),
-    ("zfh", Unstable(sym::riscv_target_feature)),
-    ("zfhmin", Unstable(sym::riscv_target_feature)),
-    ("zfinx", Unstable(sym::riscv_target_feature)),
-    ("zhinx", Unstable(sym::riscv_target_feature)),
-    ("zhinxmin", Unstable(sym::riscv_target_feature)),
-    ("zk", Stable),
-    ("zkn", Stable),
-    ("zknd", Stable),
-    ("zkne", Stable),
-    ("zknh", Stable),
-    ("zkr", Stable),
-    ("zks", Stable),
-    ("zksed", Stable),
-    ("zksh", Stable),
-    ("zkt", Stable),
+    ("a", Stable, &[]),
+    ("c", Stable, &[]),
+    ("d", Unstable(sym::riscv_target_feature), &["f"]),
+    ("e", Unstable(sym::riscv_target_feature), &[]),
+    ("f", Unstable(sym::riscv_target_feature), &[]),
+    ("m", Stable, &[]),
+    ("relax", Unstable(sym::riscv_target_feature), &[]),
+    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
+    ("v", Unstable(sym::riscv_target_feature), &[]),
+    ("zba", Stable, &[]),
+    ("zbb", Stable, &[]),
+    ("zbc", Stable, &[]),
+    ("zbkb", Stable, &[]),
+    ("zbkc", Stable, &[]),
+    ("zbkx", Stable, &[]),
+    ("zbs", Stable, &[]),
+    ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
+    ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
+    ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
+    ("zfinx", Unstable(sym::riscv_target_feature), &[]),
+    ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
+    ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
+    ("zk", Stable, &["zkn", "zkr", "zkt"]),
+    ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
+    ("zknd", Stable, &[]),
+    ("zkne", Stable, &[]),
+    ("zknh", Stable, &[]),
+    ("zkr", Stable, &[]),
+    ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
+    ("zksed", Stable, &[]),
+    ("zksh", Stable, &[]),
+    ("zkt", Stable, &[]),
     // tidy-alphabetical-end
 ];
 
-const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const WASM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("atomics", Unstable(sym::wasm_target_feature)),
-    ("bulk-memory", Stable),
-    ("exception-handling", Unstable(sym::wasm_target_feature)),
-    ("extended-const", Stable),
-    ("multivalue", Unstable(sym::wasm_target_feature)),
-    ("mutable-globals", Stable),
-    ("nontrapping-fptoint", Stable),
-    ("reference-types", Unstable(sym::wasm_target_feature)),
-    ("relaxed-simd", Unstable(sym::wasm_target_feature)),
-    ("sign-ext", Stable),
-    ("simd128", Stable),
+    ("atomics", Unstable(sym::wasm_target_feature), &[]),
+    ("bulk-memory", Stable, &[]),
+    ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
+    ("extended-const", Stable, &[]),
+    ("multivalue", Unstable(sym::wasm_target_feature), &[]),
+    ("mutable-globals", Stable, &[]),
+    ("nontrapping-fptoint", Stable, &[]),
+    ("reference-types", Unstable(sym::wasm_target_feature), &[]),
+    ("relaxed-simd", Stable, &["simd128"]),
+    ("sign-ext", Stable, &[]),
+    ("simd128", Stable, &[]),
     // tidy-alphabetical-end
 ];
 
-const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))];
+const BPF_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
+    &[("alu32", Unstable(sym::bpf_target_feature), &[])];
 
-const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const CSKY_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("10e60", Unstable(sym::csky_target_feature)),
-    ("2e3", Unstable(sym::csky_target_feature)),
-    ("3e3r1", Unstable(sym::csky_target_feature)),
-    ("3e3r2", Unstable(sym::csky_target_feature)),
-    ("3e3r3", Unstable(sym::csky_target_feature)),
-    ("3e7", Unstable(sym::csky_target_feature)),
-    ("7e10", Unstable(sym::csky_target_feature)),
-    ("cache", Unstable(sym::csky_target_feature)),
-    ("doloop", Unstable(sym::csky_target_feature)),
-    ("dsp1e2", Unstable(sym::csky_target_feature)),
-    ("dspe60", Unstable(sym::csky_target_feature)),
-    ("e1", Unstable(sym::csky_target_feature)),
-    ("e2", Unstable(sym::csky_target_feature)),
-    ("edsp", Unstable(sym::csky_target_feature)),
-    ("elrw", Unstable(sym::csky_target_feature)),
-    ("float1e2", Unstable(sym::csky_target_feature)),
-    ("float1e3", Unstable(sym::csky_target_feature)),
-    ("float3e4", Unstable(sym::csky_target_feature)),
-    ("float7e60", Unstable(sym::csky_target_feature)),
-    ("floate1", Unstable(sym::csky_target_feature)),
-    ("hard-tp", Unstable(sym::csky_target_feature)),
-    ("high-registers", Unstable(sym::csky_target_feature)),
-    ("hwdiv", Unstable(sym::csky_target_feature)),
-    ("mp", Unstable(sym::csky_target_feature)),
-    ("mp1e2", Unstable(sym::csky_target_feature)),
-    ("nvic", Unstable(sym::csky_target_feature)),
-    ("trust", Unstable(sym::csky_target_feature)),
-    ("vdsp2e60f", Unstable(sym::csky_target_feature)),
-    ("vdspv1", Unstable(sym::csky_target_feature)),
-    ("vdspv2", Unstable(sym::csky_target_feature)),
+    ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
+    ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
+    ("3e3r1", Unstable(sym::csky_target_feature), &[]),
+    ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
+    ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
+    ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
+    ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
+    ("cache", Unstable(sym::csky_target_feature), &[]),
+    ("doloop", Unstable(sym::csky_target_feature), &[]),
+    ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
+    ("dspe60", Unstable(sym::csky_target_feature), &[]),
+    ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
+    ("e2", Unstable(sym::csky_target_feature), &["e2"]),
+    ("edsp", Unstable(sym::csky_target_feature), &[]),
+    ("elrw", Unstable(sym::csky_target_feature), &[]),
+    ("float1e2", Unstable(sym::csky_target_feature), &[]),
+    ("float1e3", Unstable(sym::csky_target_feature), &[]),
+    ("float3e4", Unstable(sym::csky_target_feature), &[]),
+    ("float7e60", Unstable(sym::csky_target_feature), &[]),
+    ("floate1", Unstable(sym::csky_target_feature), &[]),
+    ("hard-tp", Unstable(sym::csky_target_feature), &[]),
+    ("high-registers", Unstable(sym::csky_target_feature), &[]),
+    ("hwdiv", Unstable(sym::csky_target_feature), &[]),
+    ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
+    ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
+    ("nvic", Unstable(sym::csky_target_feature), &[]),
+    ("trust", Unstable(sym::csky_target_feature), &[]),
+    ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
+    ("vdspv1", Unstable(sym::csky_target_feature), &[]),
+    ("vdspv2", Unstable(sym::csky_target_feature), &[]),
     // tidy-alphabetical-end
     //fpu
     // tidy-alphabetical-start
-    ("fdivdu", Unstable(sym::csky_target_feature)),
-    ("fpuv2_df", Unstable(sym::csky_target_feature)),
-    ("fpuv2_sf", Unstable(sym::csky_target_feature)),
-    ("fpuv3_df", Unstable(sym::csky_target_feature)),
-    ("fpuv3_hf", Unstable(sym::csky_target_feature)),
-    ("fpuv3_hi", Unstable(sym::csky_target_feature)),
-    ("fpuv3_sf", Unstable(sym::csky_target_feature)),
-    ("hard-float", Unstable(sym::csky_target_feature)),
-    ("hard-float-abi", Unstable(sym::csky_target_feature)),
+    ("fdivdu", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
+    ("hard-float", Unstable(sym::csky_target_feature), &[]),
+    ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("d", Unstable(sym::loongarch_target_feature)),
-    ("f", Unstable(sym::loongarch_target_feature)),
-    ("frecipe", Unstable(sym::loongarch_target_feature)),
-    ("lasx", Unstable(sym::loongarch_target_feature)),
-    ("lbt", Unstable(sym::loongarch_target_feature)),
-    ("lsx", Unstable(sym::loongarch_target_feature)),
-    ("lvz", Unstable(sym::loongarch_target_feature)),
-    ("relax", Unstable(sym::loongarch_target_feature)),
-    ("ual", Unstable(sym::loongarch_target_feature)),
+    ("d", Unstable(sym::loongarch_target_feature), &["f"]),
+    ("f", Unstable(sym::loongarch_target_feature), &[]),
+    ("frecipe", Unstable(sym::loongarch_target_feature), &[]),
+    ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]),
+    ("lbt", Unstable(sym::loongarch_target_feature), &[]),
+    ("lsx", Unstable(sym::loongarch_target_feature), &["d"]),
+    ("lvz", Unstable(sym::loongarch_target_feature), &[]),
+    ("relax", Unstable(sym::loongarch_target_feature), &[]),
+    ("ual", Unstable(sym::loongarch_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[
+const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("backchain", Unstable(sym::s390x_target_feature)),
-    ("vector", Unstable(sym::s390x_target_feature)),
+    ("backchain", Unstable(sym::s390x_target_feature), &[]),
+    ("vector", Unstable(sym::s390x_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
@@ -425,10 +448,13 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
         .chain(LOONGARCH_ALLOWED_FEATURES)
         .chain(IBMZ_ALLOWED_FEATURES)
         .cloned()
+        .map(|(f, s, _)| (f, s))
 }
 
 impl super::spec::Target {
-    pub fn supported_target_features(&self) -> &'static [(&'static str, Stability)] {
+    pub fn supported_target_features(
+        &self,
+    ) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
         match &*self.arch {
             "arm" => ARM_ALLOWED_FEATURES,
             "aarch64" | "arm64ec" => AARCH64_ALLOWED_FEATURES,
@@ -452,4 +478,28 @@ impl super::spec::Target {
             _ => &[],
         }
     }
+
+    pub fn implied_target_features(
+        &self,
+        base_features: impl Iterator<Item = Symbol>,
+    ) -> FxHashSet<Symbol> {
+        let implied_features = self
+            .supported_target_features()
+            .iter()
+            .map(|(f, _, i)| (Symbol::intern(f), i))
+            .collect::<FxHashMap<_, _>>();
+
+        // implied target features have their own implied target features, so we traverse the
+        // map until there are no more features to add
+        let mut features = FxHashSet::default();
+        let mut new_features = base_features.collect::<Vec<Symbol>>();
+        while let Some(new_feature) = new_features.pop() {
+            if features.insert(new_feature) {
+                if let Some(implied_features) = implied_features.get(&new_feature) {
+                    new_features.extend(implied_features.iter().copied().map(Symbol::intern))
+                }
+            }
+        }
+        features
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 72a4d4c1205..9ab47057859 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -388,39 +388,67 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 trait_impls.non_blanket_impls().values().flatten().count();
                             // If there is only one implementation of the trait, suggest using it.
                             // Otherwise, use a placeholder comment for the implementation.
-                            let (message, self_type) = if non_blanket_impl_count == 1 {
+                            let (message, self_types) = if non_blanket_impl_count == 1 {
                                 (
                                     "use the fully-qualified path to the only available \
                                      implementation",
-                                    format!(
+                                    vec![format!(
                                         "{}",
                                         self.tcx.type_of(impl_def_id).instantiate_identity()
-                                    ),
+                                    )],
+                                )
+                            } else if non_blanket_impl_count < 20 {
+                                (
+                                    "use a fully-qualified path to one of the available \
+                                     implementations",
+                                    trait_impls
+                                        .non_blanket_impls()
+                                        .values()
+                                        .flatten()
+                                        .map(|id| {
+                                            format!(
+                                                "{}",
+                                                self.tcx.type_of(id).instantiate_identity()
+                                            )
+                                        })
+                                        .collect::<Vec<String>>(),
                                 )
                             } else {
                                 (
                                     "use a fully-qualified path to a specific available \
                                      implementation",
-                                    "/* self type */".to_string(),
+                                    vec!["/* self type */".to_string()],
                                 )
                             };
-                            let mut suggestions =
-                                vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
-                            if let Some(generic_arg) = trait_path_segment.args {
-                                let between_span =
-                                    trait_path_segment.ident.span.between(generic_arg.span_ext);
-                                // get rid of :: between Trait and <type>
-                                // must be '::' between them, otherwise the parser won't accept the code
-                                suggestions.push((between_span, "".to_string()));
-                                suggestions
-                                    .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
-                            } else {
-                                suggestions.push((
-                                    trait_path_segment.ident.span.shrink_to_hi(),
-                                    ">".to_string(),
-                                ));
-                            }
-                            err.multipart_suggestion(
+                            let suggestions: Vec<_> = self_types
+                                .into_iter()
+                                .map(|self_type| {
+                                    let mut suggestions = vec![(
+                                        path.span.shrink_to_lo(),
+                                        format!("<{self_type} as "),
+                                    )];
+                                    if let Some(generic_arg) = trait_path_segment.args {
+                                        let between_span = trait_path_segment
+                                            .ident
+                                            .span
+                                            .between(generic_arg.span_ext);
+                                        // get rid of :: between Trait and <type>
+                                        // must be '::' between them, otherwise the parser won't accept the code
+                                        suggestions.push((between_span, "".to_string()));
+                                        suggestions.push((
+                                            generic_arg.span_ext.shrink_to_hi(),
+                                            ">".to_string(),
+                                        ));
+                                    } else {
+                                        suggestions.push((
+                                            trait_path_segment.ident.span.shrink_to_hi(),
+                                            ">".to_string(),
+                                        ));
+                                    }
+                                    suggestions
+                                })
+                                .collect();
+                            err.multipart_suggestions(
                                 message,
                                 suggestions,
                                 Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 2ce1b955af5..1cee82f04ea 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -5,10 +5,11 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
 use rustc_errors::{
-    pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, StringPart,
+    pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey,
+    StringPart,
 };
 use rustc_hir::def::Namespace;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{self as hir, LangItem, Node};
 use rustc_infer::infer::{InferOk, TypeTrace};
@@ -1624,9 +1625,131 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         other: bool,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
-        // If we have a single implementation, try to unify it with the trait ref
-        // that failed. This should uncover a better hint for what *is* implemented.
+        let alternative_candidates = |def_id: DefId| {
+            let mut impl_candidates: Vec<_> = self
+                .tcx
+                .all_impls(def_id)
+                // ignore `do_not_recommend` items
+                .filter(|def_id| {
+                    !self
+                        .tcx
+                        .has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend])
+                })
+                // Ignore automatically derived impls and `!Trait` impls.
+                .filter_map(|def_id| self.tcx.impl_trait_header(def_id))
+                .filter_map(|header| {
+                    (header.polarity != ty::ImplPolarity::Negative
+                        || self.tcx.is_automatically_derived(def_id))
+                    .then(|| header.trait_ref.instantiate_identity())
+                })
+                .filter(|trait_ref| {
+                    let self_ty = trait_ref.self_ty();
+                    // Avoid mentioning type parameters.
+                    if let ty::Param(_) = self_ty.kind() {
+                        false
+                    }
+                    // Avoid mentioning types that are private to another crate
+                    else if let ty::Adt(def, _) = self_ty.peel_refs().kind() {
+                        // FIXME(compiler-errors): This could be generalized, both to
+                        // be more granular, and probably look past other `#[fundamental]`
+                        // types, too.
+                        self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx)
+                    } else {
+                        true
+                    }
+                })
+                .collect();
+
+            impl_candidates.sort_by_key(|tr| tr.to_string());
+            impl_candidates.dedup();
+            impl_candidates
+        };
+
+        // We'll check for the case where the reason for the mismatch is that the trait comes from
+        // one crate version and the type comes from another crate version, even though they both
+        // are from the same crate.
+        let trait_def_id = trait_ref.def_id();
+        if let ty::Adt(def, _) = trait_ref.self_ty().skip_binder().peel_refs().kind()
+            && let found_type = def.did()
+            && trait_def_id.krate != found_type.krate
+            && self.tcx.crate_name(trait_def_id.krate) == self.tcx.crate_name(found_type.krate)
+        {
+            let name = self.tcx.crate_name(trait_def_id.krate);
+            let spans: Vec<_> = [trait_def_id, found_type]
+                .into_iter()
+                .filter_map(|def_id| self.tcx.extern_crate(def_id))
+                .map(|data| {
+                    let dependency = if data.dependency_of == LOCAL_CRATE {
+                        "direct dependency of the current crate".to_string()
+                    } else {
+                        let dep = self.tcx.crate_name(data.dependency_of);
+                        format!("dependency of crate `{dep}`")
+                    };
+                    (
+                        data.span,
+                        format!("one version of crate `{name}` is used here, as a {dependency}"),
+                    )
+                })
+                .collect();
+            let mut span: MultiSpan = spans.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
+            for (sp, label) in spans.into_iter() {
+                span.push_span_label(sp, label);
+            }
+            err.highlighted_span_help(
+                span,
+                vec![
+                    StringPart::normal("you have ".to_string()),
+                    StringPart::highlighted("multiple different versions".to_string()),
+                    StringPart::normal(" of crate `".to_string()),
+                    StringPart::highlighted(format!("{name}")),
+                    StringPart::normal("` in your dependency graph".to_string()),
+                ],
+            );
+            let candidates = if impl_candidates.is_empty() {
+                alternative_candidates(trait_def_id)
+            } else {
+                impl_candidates.into_iter().map(|cand| cand.trait_ref).collect()
+            };
+            if let Some((sp_candidate, sp_found)) = candidates.iter().find_map(|trait_ref| {
+                if let ty::Adt(def, _) = trait_ref.self_ty().peel_refs().kind()
+                    && let candidate_def_id = def.did()
+                    && let Some(name) = self.tcx.opt_item_name(candidate_def_id)
+                    && let Some(found) = self.tcx.opt_item_name(found_type)
+                    && name == found
+                    && candidate_def_id.krate != found_type.krate
+                    && self.tcx.crate_name(candidate_def_id.krate)
+                        == self.tcx.crate_name(found_type.krate)
+                {
+                    // A candidate was found of an item with the same name, from two separate
+                    // versions of the same crate, let's clarify.
+                    Some((self.tcx.def_span(candidate_def_id), self.tcx.def_span(found_type)))
+                } else {
+                    None
+                }
+            }) {
+                let mut span: MultiSpan = vec![sp_candidate, sp_found].into();
+                span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait");
+                span.push_span_label(sp_candidate, "this type implements the required trait");
+                span.push_span_label(sp_found, "this type doesn't implement the required trait");
+                err.highlighted_span_note(
+                    span,
+                    vec![
+                        StringPart::normal(
+                            "two types coming from two different versions of the same crate are \
+                             different types "
+                                .to_string(),
+                        ),
+                        StringPart::highlighted("even if they look the same".to_string()),
+                    ],
+                );
+            }
+            err.help("you can use `cargo tree` to explore your dependency tree");
+            return true;
+        }
+
         if let [single] = &impl_candidates {
+            // If we have a single implementation, try to unify it with the trait ref
+            // that failed. This should uncover a better hint for what *is* implemented.
             if self.probe(|_| {
                 let ocx = ObligationCtxt::new(self);
 
@@ -1798,43 +1921,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // Mentioning implementers of `Copy`, `Debug` and friends is not useful.
                 return false;
             }
-            let mut impl_candidates: Vec<_> = self
-                .tcx
-                .all_impls(def_id)
-                // ignore `do_not_recommend` items
-                .filter(|def_id| {
-                    !self
-                        .tcx
-                        .has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend])
-                })
-                // Ignore automatically derived impls and `!Trait` impls.
-                .filter_map(|def_id| self.tcx.impl_trait_header(def_id))
-                .filter_map(|header| {
-                    (header.polarity != ty::ImplPolarity::Negative
-                        || self.tcx.is_automatically_derived(def_id))
-                    .then(|| header.trait_ref.instantiate_identity())
-                })
-                .filter(|trait_ref| {
-                    let self_ty = trait_ref.self_ty();
-                    // Avoid mentioning type parameters.
-                    if let ty::Param(_) = self_ty.kind() {
-                        false
-                    }
-                    // Avoid mentioning types that are private to another crate
-                    else if let ty::Adt(def, _) = self_ty.peel_refs().kind() {
-                        // FIXME(compiler-errors): This could be generalized, both to
-                        // be more granular, and probably look past other `#[fundamental]`
-                        // types, too.
-                        self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx)
-                    } else {
-                        true
-                    }
-                })
-                .collect();
-
-            impl_candidates.sort_by_key(|tr| tr.to_string());
-            impl_candidates.dedup();
-            return report(impl_candidates, err);
+            return report(alternative_candidates(def_id), err);
         }
 
         // Sort impl candidates so that ordering is consistent for UI tests.
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index f7b8d99593e..a350b76a704 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -62,7 +62,7 @@ pub use self::specialize::{
 };
 pub use self::structural_normalize::StructurallyNormalizeExt;
 pub use self::util::{
-    elaborate, expand_trait_aliases, impl_item_is_final, supertraits, transitive_bounds,
+    elaborate, expand_trait_aliases, impl_item_is_final, supertraits,
     transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars,
     BoundVarReplacer, PlaceholderReplacer, TraitAliasExpander, TraitAliasExpansionInfo,
 };
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 2085d3da443..9de62031311 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -467,8 +467,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
                 candidates.vec.push(AsyncClosureCandidate);
             }
-            ty::FnDef(..) | ty::FnPtr(..) => {
-                candidates.vec.push(AsyncClosureCandidate);
+            // Provide an impl, but only for suitable `fn` pointers.
+            ty::FnPtr(sig) => {
+                if sig.is_fn_trait_compatible() {
+                    candidates.vec.push(AsyncClosureCandidate);
+                }
+            }
+            // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
+            ty::FnDef(def_id, _) => {
+                let tcx = self.tcx();
+                if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
+                    && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+                {
+                    candidates.vec.push(AsyncClosureCandidate);
+                }
             }
             _ => {}
         }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index cc9174d3aad..1b2767a6a62 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -7,6 +7,7 @@ use std::fmt::{self, Display};
 use std::ops::ControlFlow;
 use std::{cmp, iter};
 
+use hir::def::DefKind;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Diag, EmissionGuarantee};
@@ -14,8 +15,8 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
 use rustc_infer::infer::relate::TypeRelation;
-use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
-use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
+use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::TraitObligation;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{dep_kinds, DepNodeIndex};
@@ -2798,6 +2799,26 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             });
         }
 
+        // Register any outlives obligations from the trait here, cc #124336.
+        if matches!(tcx.def_kind(def_id), DefKind::Impl { of_trait: true }) {
+            for clause in tcx.impl_super_outlives(def_id).iter_instantiated(tcx, args) {
+                let clause = normalize_with_depth_to(
+                    self,
+                    param_env,
+                    cause.clone(),
+                    recursion_depth,
+                    clause,
+                    &mut obligations,
+                );
+                obligations.push(Obligation {
+                    cause: cause.clone(),
+                    recursion_depth,
+                    param_env,
+                    predicate: clause.as_predicate(),
+                });
+            }
+        }
+
         obligations
     }
 }
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
index 0dd26badc88..5db5a8f222d 100644
--- a/compiler/rustc_transmute/src/layout/nfa.rs
+++ b/compiler/rustc_transmute/src/layout/nfa.rs
@@ -87,6 +87,7 @@ where
     pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
         Ok(match tree {
             Tree::Byte(b) => Self::from_byte(b),
+            #[cfg(bootstrap)]
             Tree::Def(..) => unreachable!(),
             Tree::Ref(r) => Self::from_ref(r),
             Tree::Alt(alts) => {
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index f1675f80717..d90c3bedc70 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -549,7 +549,7 @@ fn fn_abi_sanity_check<'tcx>(
                 // With metadata. Must be unsized and not on the stack.
                 assert!(arg.layout.is_unsized() && !on_stack);
                 // Also, must not be `extern` type.
-                let tail = cx.tcx.struct_tail_with_normalize(arg.layout.ty, |ty| ty, || {});
+                let tail = cx.tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
                 if matches!(tail.kind(), ty::Foreign(..)) {
                     // These types do not have metadata, so having `meta_attrs` is bogus.
                     // Conceptually, unsized arguments must be copied around, which requires dynamically
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 3ef10f4e43c..1eb03fc3bd6 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -244,7 +244,7 @@ fn layout_of_uncached<'tcx>(
 
                 metadata
             } else {
-                let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
+                let unsized_part = tcx.struct_tail_for_codegen(pointee, param_env);
 
                 match unsized_part.kind() {
                     ty::Foreign(..) => {
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 0246996c27f..f30419c801f 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -264,15 +264,6 @@ pub fn supertraits<I: Interner>(
     elaborate(cx, [trait_ref.upcast(cx)]).filter_only_self().filter_to_traits()
 }
 
-pub fn transitive_bounds<I: Interner>(
-    cx: I,
-    trait_refs: impl Iterator<Item = ty::Binder<I, ty::TraitRef<I>>>,
-) -> FilterToTraits<I, Elaborator<I, I::Clause>> {
-    elaborate(cx, trait_refs.map(|trait_ref| trait_ref.upcast(cx)))
-        .filter_only_self()
-        .filter_to_traits()
-}
-
 impl<I: Interner> Elaborator<I, I::Clause> {
     fn filter_to_traits(self) -> FilterToTraits<I, Self> {
         FilterToTraits { _cx: PhantomData, base_iterator: self }
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index 16dcf76e73e..d37bacc7d35 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -91,6 +91,7 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
     fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
         match self.try_fold_with(folder) {
             Ok(t) => t,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
@@ -115,6 +116,7 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
     fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
         match self.try_super_fold_with(folder) {
             Ok(t) => t,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index e1a3764fa76..263ba676427 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -451,6 +451,8 @@ pub trait Clause<I: Interner<Clause = Self>>:
     + UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
     + UpcastFrom<I, ty::TraitRef<I>>
     + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+    + UpcastFrom<I, ty::TraitPredicate<I>>
+    + UpcastFrom<I, ty::Binder<I, ty::TraitPredicate<I>>>
     + UpcastFrom<I, ty::ProjectionPredicate<I>>
     + UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
     + IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
diff --git a/config.example.toml b/config.example.toml
index 45faa66ec11..1b7de662e84 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -87,6 +87,9 @@
 # library provided by LLVM.
 #static-libstdcpp = false
 
+# Enable LLVM to use zstd for compression.
+#libzstd = false
+
 # Whether to use Ninja to build LLVM. This runs much faster than make.
 #ninja = true
 
@@ -472,7 +475,8 @@
 # This is mostly useful for tools; if you have changes to `compiler/` or `library/` they will be ignored.
 #
 # Set this to "if-unchanged" to only download if the compiler and standard library have not been modified.
-# Set this to `true` to download unconditionally (useful if e.g. you are only changing doc-comments).
+# Set this to `true` to download unconditionally. This is useful if you are working on tools, doc-comments,
+# or library (you will be able to build the standard library without needing to build the compiler).
 #download-rustc = false
 
 # Number of codegen units to use for each compiler invocation. A value of 0
diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/library/Cargo.lock
index 9ea53e8f848..b36399d880e 100644
--- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
+++ b/library/Cargo.lock
@@ -36,15 +36,15 @@ dependencies = [
 
 [[package]]
 name = "allocator-api2"
-version = "0.2.16"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
 
 [[package]]
 name = "cc"
-version = "1.0.97"
+version = "1.0.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
+checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
 
 [[package]]
 name = "cfg-if"
@@ -58,9 +58,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.106"
+version = "0.1.118"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4ab134a739bafec76aa91ccb15d519a54e569350644a1fea6528d5a0d407e22"
+checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -75,24 +75,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "cupid"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bad352a84b567cc38a5854e3aa8ee903cb8519a25d0b799b739bafffd1f91a1"
-dependencies = [
- "gcc",
- "rustc_version",
-]
-
-[[package]]
 name = "dlmalloc"
-version = "0.2.4"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a"
+checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d"
 dependencies = [
+ "cfg-if",
  "compiler_builtins",
  "libc",
  "rustc-std-workspace-core",
+ "windows-sys",
 ]
 
 [[package]]
@@ -106,12 +98,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "gcc"
-version = "0.3.55"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
-
-[[package]]
 name = "getopts"
 version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -146,9 +132,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.14.3"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 dependencies = [
  "allocator-api2",
  "compiler_builtins",
@@ -169,18 +155,18 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.153"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 dependencies = [
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "memchr"
-version = "2.6.4"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -188,9 +174,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.1"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
 dependencies = [
  "adler",
  "compiler_builtins",
@@ -200,9 +186,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.36.0"
+version = "0.36.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
+checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
 dependencies = [
  "compiler_builtins",
  "memchr",
@@ -252,9 +238,9 @@ dependencies = [
 
 [[package]]
 name = "r-efi"
-version = "4.3.0"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e244f96e03a3067f9e521d3167bd42657594cb8588c8d3a2db01545dc1af2e0"
+checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -327,30 +313,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-dependencies = [
- "semver",
-]
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
-[[package]]
 name = "std"
 version = "0.0.0"
 dependencies = [
@@ -385,7 +347,6 @@ version = "0.1.5"
 dependencies = [
  "cfg-if",
  "compiler_builtins",
- "cupid",
  "libc",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -412,9 +373,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-width"
-version = "0.1.11"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -453,3 +414,76 @@ dependencies = [
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
diff --git a/library/Cargo.toml b/library/Cargo.toml
new file mode 100644
index 00000000000..c4513b4c127
--- /dev/null
+++ b/library/Cargo.toml
@@ -0,0 +1,44 @@
+[workspace]
+resolver = "1"
+members = [
+  "std",
+  "sysroot",
+]
+
+exclude = [
+  # stdarch has its own Cargo workspace
+  "stdarch",
+]
+
+[profile.release.package.compiler_builtins]
+# For compiler-builtins we always use a high number of codegen units.
+# The goal here is to place every single intrinsic into its own object
+# file to avoid symbol clashes with the system libgcc if possible. Note
+# that this number doesn't actually produce this many object files, we
+# just don't create more than this number of object files.
+#
+# It's a bit of a bummer that we have to pass this here, unfortunately.
+# Ideally this would be specified through an env var to Cargo so Cargo
+# knows how many CGUs are for this specific crate, but for now
+# per-crate configuration isn't specifiable in the environment.
+codegen-units = 10000
+
+# These dependencies of the standard library implement symbolication for
+# backtraces on most platforms. Their debuginfo causes both linking to be slower
+# (more data to chew through) and binaries to be larger without really all that
+# much benefit. This section turns them all to down to have no debuginfo which
+# helps to improve link times a little bit.
+[profile.release.package]
+addr2line.debug = 0
+adler.debug = 0
+gimli.debug = 0
+miniz_oxide.debug = 0
+object.debug = 0
+rustc-demangle.debug = 0
+
+[patch.crates-io]
+# See comments in `library/rustc-std-workspace-core/README.md` for what's going on
+# here
+rustc-std-workspace-core = { path = 'rustc-std-workspace-core' }
+rustc-std-workspace-alloc = { path = 'rustc-std-workspace-alloc' }
+rustc-std-workspace-std = { path = 'rustc-std-workspace-std' }
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 479eb0a2ba7..bdf16257c7c 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -10,10 +10,7 @@ edition = "2021"
 
 [dependencies]
 core = { path = "../core" }
-compiler_builtins = { version = "0.1.114", features = ['rustc-dep-of-std'] }
-
-[target.'cfg(not(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")))'.dependencies]
-compiler_builtins = { version = "0.1.114", features = ["no-f16-f128"] }
+compiler_builtins = { version = "0.1.118", features = ['rustc-dep-of-std'] }
 
 [dev-dependencies]
 rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index ef40d3b203f..7de41259599 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -200,7 +200,7 @@ use core::ops::{
     AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut,
     DerefPure, DispatchFromDyn, Receiver,
 };
-use core::pin::Pin;
+use core::pin::{Pin, PinCoerceUnsized};
 use core::ptr::{self, addr_of_mut, NonNull, Unique};
 use core::task::{Context, Poll};
 use core::{borrow, fmt, slice};
@@ -1173,6 +1173,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// ```
     ///
     /// [memory layout]: self#memory-layout
+    #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "box_raw", since = "1.4.0")]
     #[inline]
     pub fn into_raw(b: Self) -> *mut T {
@@ -1226,6 +1227,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// ```
     ///
     /// [memory layout]: self#memory-layout
+    #[must_use = "losing the pointer will leak memory"]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
@@ -2724,3 +2726,6 @@ impl<T: core::error::Error> core::error::Error for Box<T> {
         core::error::Error::provide(&**self, request);
     }
 }
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {}
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index cc5f33c3685..88701370c10 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -1433,6 +1433,20 @@ pub struct Iter<'a, T: 'a> {
     iter: slice::Iter<'a, T>,
 }
 
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
+impl<T> Default for Iter<'_, T> {
+    /// Creates an empty `binary_heap::Iter`.
+    ///
+    /// ```
+    /// # use std::collections::binary_heap;
+    /// let iter: binary_heap::Iter<'_, u8> = Default::default();
+    /// assert_eq!(iter.len(), 0);
+    /// ```
+    fn default() -> Self {
+        Iter { iter: Default::default() }
+    }
+}
+
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index d84654e36d7..f6f773cc42a 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -2016,6 +2016,20 @@ impl<K, V> Default for Range<'_, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for RangeMut<'_, K, V> {
+    /// Creates an empty `btree_map::RangeMut`.
+    ///
+    /// ```
+    /// # use std::collections::btree_map;
+    /// let iter: btree_map::RangeMut<'_, u8, u8> = Default::default();
+    /// assert_eq!(iter.count(), 0);
+    /// ```
+    fn default() -> Self {
+        RangeMut { inner: Default::default(), _marker: PhantomData }
+    }
+}
+
 #[stable(feature = "map_values_mut", since = "1.10.0")]
 impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
     type Item = &'a mut V;
@@ -2050,6 +2064,20 @@ impl<K, V> ExactSizeIterator for ValuesMut<'_, K, V> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl<K, V> FusedIterator for ValuesMut<'_, K, V> {}
 
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for ValuesMut<'_, K, V> {
+    /// Creates an empty `btree_map::ValuesMut`.
+    ///
+    /// ```
+    /// # use std::collections::btree_map;
+    /// let iter: btree_map::ValuesMut<'_, u8, u8> = Default::default();
+    /// assert_eq!(iter.count(), 0);
+    /// ```
+    fn default() -> Self {
+        ValuesMut { inner: Default::default() }
+    }
+}
+
 #[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V, A: Allocator + Clone> Iterator for IntoKeys<K, V, A> {
     type Item = K;
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 74b000fd1c4..973e7c66067 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -5,7 +5,7 @@ use core::fmt::{self, Debug};
 use core::hash::{Hash, Hasher};
 use core::iter::{FusedIterator, Peekable};
 use core::mem::ManuallyDrop;
-use core::ops::{BitAnd, BitOr, BitXor, RangeBounds, Sub};
+use core::ops::{BitAnd, BitOr, BitXor, Bound, RangeBounds, Sub};
 
 use super::map::{BTreeMap, Keys};
 use super::merge_iter::MergeIterInner;
@@ -1182,6 +1182,178 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
+
+    /// Returns a [`Cursor`] pointing at the gap before the smallest element
+    /// greater than the given bound.
+    ///
+    /// Passing `Bound::Included(x)` will return a cursor pointing to the
+    /// gap before the smallest element greater than or equal to `x`.
+    ///
+    /// Passing `Bound::Excluded(x)` will return a cursor pointing to the
+    /// gap before the smallest element greater than `x`.
+    ///
+    /// Passing `Bound::Unbounded` will return a cursor pointing to the
+    /// gap before the smallest element in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeSet;
+    /// use std::ops::Bound;
+    ///
+    /// let set = BTreeSet::from([1, 2, 3, 4]);
+    ///
+    /// let cursor = set.lower_bound(Bound::Included(&2));
+    /// assert_eq!(cursor.peek_prev(), Some(&1));
+    /// assert_eq!(cursor.peek_next(), Some(&2));
+    ///
+    /// let cursor = set.lower_bound(Bound::Excluded(&2));
+    /// assert_eq!(cursor.peek_prev(), Some(&2));
+    /// assert_eq!(cursor.peek_next(), Some(&3));
+    ///
+    /// let cursor = set.lower_bound(Bound::Unbounded);
+    /// assert_eq!(cursor.peek_prev(), None);
+    /// assert_eq!(cursor.peek_next(), Some(&1));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn lower_bound<Q: ?Sized>(&self, bound: Bound<&Q>) -> Cursor<'_, T>
+    where
+        T: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        Cursor { inner: self.map.lower_bound(bound) }
+    }
+
+    /// Returns a [`CursorMut`] pointing at the gap before the smallest element
+    /// greater than the given bound.
+    ///
+    /// Passing `Bound::Included(x)` will return a cursor pointing to the
+    /// gap before the smallest element greater than or equal to `x`.
+    ///
+    /// Passing `Bound::Excluded(x)` will return a cursor pointing to the
+    /// gap before the smallest element greater than `x`.
+    ///
+    /// Passing `Bound::Unbounded` will return a cursor pointing to the
+    /// gap before the smallest element in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeSet;
+    /// use std::ops::Bound;
+    ///
+    /// let mut set = BTreeSet::from([1, 2, 3, 4]);
+    ///
+    /// let mut cursor = set.lower_bound_mut(Bound::Included(&2));
+    /// assert_eq!(cursor.peek_prev(), Some(&1));
+    /// assert_eq!(cursor.peek_next(), Some(&2));
+    ///
+    /// let mut cursor = set.lower_bound_mut(Bound::Excluded(&2));
+    /// assert_eq!(cursor.peek_prev(), Some(&2));
+    /// assert_eq!(cursor.peek_next(), Some(&3));
+    ///
+    /// let mut cursor = set.lower_bound_mut(Bound::Unbounded);
+    /// assert_eq!(cursor.peek_prev(), None);
+    /// assert_eq!(cursor.peek_next(), Some(&1));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn lower_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A>
+    where
+        T: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        CursorMut { inner: self.map.lower_bound_mut(bound) }
+    }
+
+    /// Returns a [`Cursor`] pointing at the gap after the greatest element
+    /// smaller than the given bound.
+    ///
+    /// Passing `Bound::Included(x)` will return a cursor pointing to the
+    /// gap after the greatest element smaller than or equal to `x`.
+    ///
+    /// Passing `Bound::Excluded(x)` will return a cursor pointing to the
+    /// gap after the greatest element smaller than `x`.
+    ///
+    /// Passing `Bound::Unbounded` will return a cursor pointing to the
+    /// gap after the greatest element in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeSet;
+    /// use std::ops::Bound;
+    ///
+    /// let set = BTreeSet::from([1, 2, 3, 4]);
+    ///
+    /// let cursor = set.upper_bound(Bound::Included(&3));
+    /// assert_eq!(cursor.peek_prev(), Some(&3));
+    /// assert_eq!(cursor.peek_next(), Some(&4));
+    ///
+    /// let cursor = set.upper_bound(Bound::Excluded(&3));
+    /// assert_eq!(cursor.peek_prev(), Some(&2));
+    /// assert_eq!(cursor.peek_next(), Some(&3));
+    ///
+    /// let cursor = set.upper_bound(Bound::Unbounded);
+    /// assert_eq!(cursor.peek_prev(), Some(&4));
+    /// assert_eq!(cursor.peek_next(), None);
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn upper_bound<Q: ?Sized>(&self, bound: Bound<&Q>) -> Cursor<'_, T>
+    where
+        T: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        Cursor { inner: self.map.upper_bound(bound) }
+    }
+
+    /// Returns a [`CursorMut`] pointing at the gap after the greatest element
+    /// smaller than the given bound.
+    ///
+    /// Passing `Bound::Included(x)` will return a cursor pointing to the
+    /// gap after the greatest element smaller than or equal to `x`.
+    ///
+    /// Passing `Bound::Excluded(x)` will return a cursor pointing to the
+    /// gap after the greatest element smaller than `x`.
+    ///
+    /// Passing `Bound::Unbounded` will return a cursor pointing to the
+    /// gap after the greatest element in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeSet;
+    /// use std::ops::Bound;
+    ///
+    /// let mut set = BTreeSet::from([1, 2, 3, 4]);
+    ///
+    /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Included(&3)) };
+    /// assert_eq!(cursor.peek_prev(), Some(&3));
+    /// assert_eq!(cursor.peek_next(), Some(&4));
+    ///
+    /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Excluded(&3)) };
+    /// assert_eq!(cursor.peek_prev(), Some(&2));
+    /// assert_eq!(cursor.peek_next(), Some(&3));
+    ///
+    /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Unbounded) };
+    /// assert_eq!(cursor.peek_prev(), Some(&4));
+    /// assert_eq!(cursor.peek_next(), None);
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A>
+    where
+        T: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        CursorMut { inner: self.map.upper_bound_mut(bound) }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1816,5 +1988,414 @@ impl<'a, T: Ord> Iterator for Union<'a, T> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl<T: Ord> FusedIterator for Union<'_, T> {}
 
+/// A cursor over a `BTreeSet`.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth.
+///
+/// Cursors always point to a gap between two elements in the set, and can
+/// operate on the two immediately adjacent elements.
+///
+/// A `Cursor` is created with the [`BTreeSet::lower_bound`] and [`BTreeSet::upper_bound`] methods.
+#[derive(Clone)]
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct Cursor<'a, K: 'a> {
+    inner: super::map::Cursor<'a, K, SetValZST>,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug> Debug for Cursor<'_, K> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("Cursor")
+    }
+}
+
+/// A cursor over a `BTreeSet` with editing operations.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can
+/// safely mutate the set during iteration. This is because the lifetime of its yielded
+/// references is tied to its own lifetime, instead of just the underlying map. This means
+/// cursors cannot yield multiple elements at once.
+///
+/// Cursors always point to a gap between two elements in the set, and can
+/// operate on the two immediately adjacent elements.
+///
+/// A `CursorMut` is created with the [`BTreeSet::lower_bound_mut`] and [`BTreeSet::upper_bound_mut`]
+/// methods.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct CursorMut<'a, K: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A = Global>
+{
+    inner: super::map::CursorMut<'a, K, SetValZST, A>,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, A> Debug for CursorMut<'_, K, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("CursorMut")
+    }
+}
+
+/// A cursor over a `BTreeSet` with editing operations, and which allows
+/// mutating elements.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can
+/// safely mutate the set during iteration. This is because the lifetime of its yielded
+/// references is tied to its own lifetime, instead of just the underlying set. This means
+/// cursors cannot yield multiple elements at once.
+///
+/// Cursors always point to a gap between two elements in the set, and can
+/// operate on the two immediately adjacent elements.
+///
+/// A `CursorMutKey` is created from a [`CursorMut`] with the
+/// [`CursorMut::with_mutable_key`] method.
+///
+/// # Safety
+///
+/// Since this cursor allows mutating elements, you must ensure that the
+/// `BTreeSet` invariants are maintained. Specifically:
+///
+/// * The newly inserted element must be unique in the tree.
+/// * All elements in the tree must remain in sorted order.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct CursorMutKey<
+    'a,
+    K: 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A = Global,
+> {
+    inner: super::map::CursorMutKey<'a, K, SetValZST, A>,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, A> Debug for CursorMutKey<'_, K, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("CursorMutKey")
+    }
+}
+
+impl<'a, K> Cursor<'a, K> {
+    /// Advances the cursor to the next gap, returning the element that it
+    /// moved over.
+    ///
+    /// If the cursor is already at the end of the set then `None` is returned
+    /// and the cursor is not moved.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn next(&mut self) -> Option<&'a K> {
+        self.inner.next().map(|(k, _)| k)
+    }
+
+    /// Advances the cursor to the previous gap, returning the element that it
+    /// moved over.
+    ///
+    /// If the cursor is already at the start of the set then `None` is returned
+    /// and the cursor is not moved.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn prev(&mut self) -> Option<&'a K> {
+        self.inner.prev().map(|(k, _)| k)
+    }
+
+    /// Returns a reference to next element without moving the cursor.
+    ///
+    /// If the cursor is at the end of the set then `None` is returned
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_next(&self) -> Option<&'a K> {
+        self.inner.peek_next().map(|(k, _)| k)
+    }
+
+    /// Returns a reference to the previous element without moving the cursor.
+    ///
+    /// If the cursor is at the start of the set then `None` is returned.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_prev(&self) -> Option<&'a K> {
+        self.inner.peek_prev().map(|(k, _)| k)
+    }
+}
+
+impl<'a, T, A> CursorMut<'a, T, A> {
+    /// Advances the cursor to the next gap, returning the element that it
+    /// moved over.
+    ///
+    /// If the cursor is already at the end of the set then `None` is returned
+    /// and the cursor is not moved.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn next(&mut self) -> Option<&T> {
+        self.inner.next().map(|(k, _)| k)
+    }
+
+    /// Advances the cursor to the previous gap, returning the element that it
+    /// moved over.
+    ///
+    /// If the cursor is already at the start of the set then `None` is returned
+    /// and the cursor is not moved.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn prev(&mut self) -> Option<&T> {
+        self.inner.prev().map(|(k, _)| k)
+    }
+
+    /// Returns a reference to the next element without moving the cursor.
+    ///
+    /// If the cursor is at the end of the set then `None` is returned.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_next(&mut self) -> Option<&T> {
+        self.inner.peek_next().map(|(k, _)| k)
+    }
+
+    /// Returns a reference to the previous element without moving the cursor.
+    ///
+    /// If the cursor is at the start of the set then `None` is returned.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_prev(&mut self) -> Option<&T> {
+        self.inner.peek_prev().map(|(k, _)| k)
+    }
+
+    /// Returns a read-only cursor pointing to the same location as the
+    /// `CursorMut`.
+    ///
+    /// The lifetime of the returned `Cursor` is bound to that of the
+    /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the
+    /// `CursorMut` is frozen for the lifetime of the `Cursor`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn as_cursor(&self) -> Cursor<'_, T> {
+        Cursor { inner: self.inner.as_cursor() }
+    }
+
+    /// Converts the cursor into a [`CursorMutKey`], which allows mutating
+    /// elements in the tree.
+    ///
+    /// # Safety
+    ///
+    /// Since this cursor allows mutating elements, you must ensure that the
+    /// `BTreeSet` invariants are maintained. Specifically:
+    ///
+    /// * The newly inserted element must be unique in the tree.
+    /// * All elements in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn with_mutable_key(self) -> CursorMutKey<'a, T, A> {
+        CursorMutKey { inner: unsafe { self.inner.with_mutable_key() } }
+    }
+}
+
+impl<'a, T, A> CursorMutKey<'a, T, A> {
+    /// Advances the cursor to the next gap, returning the  element that it
+    /// moved over.
+    ///
+    /// If the cursor is already at the end of the set then `None` is returned
+    /// and the cursor is not moved.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn next(&mut self) -> Option<&mut T> {
+        self.inner.next().map(|(k, _)| k)
+    }
+
+    /// Advances the cursor to the previous gap, returning the element that it
+    /// moved over.
+    ///
+    /// If the cursor is already at the start of the set then `None` is returned
+    /// and the cursor is not moved.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn prev(&mut self) -> Option<&mut T> {
+        self.inner.prev().map(|(k, _)| k)
+    }
+
+    /// Returns a reference to the next element without moving the cursor.
+    ///
+    /// If the cursor is at the end of the set then `None` is returned
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_next(&mut self) -> Option<&mut T> {
+        self.inner.peek_next().map(|(k, _)| k)
+    }
+
+    /// Returns a reference to the previous element without moving the cursor.
+    ///
+    /// If the cursor is at the start of the set then `None` is returned.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_prev(&mut self) -> Option<&mut T> {
+        self.inner.peek_prev().map(|(k, _)| k)
+    }
+
+    /// Returns a read-only cursor pointing to the same location as the
+    /// `CursorMutKey`.
+    ///
+    /// The lifetime of the returned `Cursor` is bound to that of the
+    /// `CursorMutKey`, which means it cannot outlive the `CursorMutKey` and that the
+    /// `CursorMutKey` is frozen for the lifetime of the `Cursor`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn as_cursor(&self) -> Cursor<'_, T> {
+        Cursor { inner: self.inner.as_cursor() }
+    }
+}
+
+impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> {
+    /// Inserts a new element into the set in the gap that the
+    /// cursor is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap before the
+    /// newly inserted element.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeSet` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The newly inserted element must be unique in the tree.
+    /// * All elements in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_after_unchecked(&mut self, value: T) {
+        unsafe { self.inner.insert_after_unchecked(value, SetValZST) }
+    }
+
+    /// Inserts a new element into the set in the gap that the
+    /// cursor is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap after the
+    /// newly inserted element.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeSet` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The newly inserted element must be unique in the tree.
+    /// * All elements in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_before_unchecked(&mut self, value: T) {
+        unsafe { self.inner.insert_before_unchecked(value, SetValZST) }
+    }
+
+    /// Inserts a new element into the set in the gap that the
+    /// cursor is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap before the
+    /// newly inserted element.
+    ///
+    /// If the inserted element is not greater than the element before the
+    /// cursor (if any), or if it not less than the element after the cursor (if
+    /// any), then an [`UnorderedKeyError`] is returned since this would
+    /// invalidate the [`Ord`] invariant between the elements of the set.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_after(&mut self, value: T) -> Result<(), UnorderedKeyError> {
+        self.inner.insert_after(value, SetValZST)
+    }
+
+    /// Inserts a new element into the set in the gap that the
+    /// cursor is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap after the
+    /// newly inserted element.
+    ///
+    /// If the inserted element is not greater than the element before the
+    /// cursor (if any), or if it not less than the element after the cursor (if
+    /// any), then an [`UnorderedKeyError`] is returned since this would
+    /// invalidate the [`Ord`] invariant between the elements of the set.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_before(&mut self, value: T) -> Result<(), UnorderedKeyError> {
+        self.inner.insert_before(value, SetValZST)
+    }
+
+    /// Removes the next element from the `BTreeSet`.
+    ///
+    /// The element that was removed is returned. The cursor position is
+    /// unchanged (before the removed element).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_next(&mut self) -> Option<T> {
+        self.inner.remove_next().map(|(k, _)| k)
+    }
+
+    /// Removes the precending element from the `BTreeSet`.
+    ///
+    /// The element that was removed is returned. The cursor position is
+    /// unchanged (after the removed element).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_prev(&mut self) -> Option<T> {
+        self.inner.remove_prev().map(|(k, _)| k)
+    }
+}
+
+impl<'a, T: Ord, A: Allocator + Clone> CursorMutKey<'a, T, A> {
+    /// Inserts a new element into the set in the gap that the
+    /// cursor is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap before the
+    /// newly inserted element.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeSet` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The key of the newly inserted element must be unique in the tree.
+    /// * All elements in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_after_unchecked(&mut self, value: T) {
+        unsafe { self.inner.insert_after_unchecked(value, SetValZST) }
+    }
+
+    /// Inserts a new element into the set in the gap that the
+    /// cursor is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap after the
+    /// newly inserted element.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeSet` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The newly inserted element must be unique in the tree.
+    /// * All elements in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_before_unchecked(&mut self, value: T) {
+        unsafe { self.inner.insert_before_unchecked(value, SetValZST) }
+    }
+
+    /// Inserts a new element into the set in the gap that the
+    /// cursor is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap before the
+    /// newly inserted element.
+    ///
+    /// If the inserted element is not greater than the element before the
+    /// cursor (if any), or if it not less than the element after the cursor (if
+    /// any), then an [`UnorderedKeyError`] is returned since this would
+    /// invalidate the [`Ord`] invariant between the elements of the set.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_after(&mut self, value: T) -> Result<(), UnorderedKeyError> {
+        self.inner.insert_after(value, SetValZST)
+    }
+
+    /// Inserts a new element into the set in the gap that the
+    /// cursor is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap after the
+    /// newly inserted element.
+    ///
+    /// If the inserted element is not greater than the element before the
+    /// cursor (if any), or if it not less than the element after the cursor (if
+    /// any), then an [`UnorderedKeyError`] is returned since this would
+    /// invalidate the [`Ord`] invariant between the elements of the set.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_before(&mut self, value: T) -> Result<(), UnorderedKeyError> {
+        self.inner.insert_before(value, SetValZST)
+    }
+
+    /// Removes the next element from the `BTreeSet`.
+    ///
+    /// The element that was removed is returned. The cursor position is
+    /// unchanged (before the removed element).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_next(&mut self) -> Option<T> {
+        self.inner.remove_next().map(|(k, _)| k)
+    }
+
+    /// Removes the precending element from the `BTreeSet`.
+    ///
+    /// The element that was removed is returned. The cursor position is
+    /// unchanged (after the removed element).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_prev(&mut self) -> Option<T> {
+        self.inner.remove_prev().map(|(k, _)| k)
+    }
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub use super::map::UnorderedKeyError;
+
 #[cfg(test)]
 mod tests;
diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs
index 2d283dac9a9..7be3de16b2d 100644
--- a/library/alloc/src/collections/vec_deque/into_iter.rs
+++ b/library/alloc/src/collections/vec_deque/into_iter.rs
@@ -121,6 +121,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     {
         match self.try_fold(init, |b, item| Ok::<B, !>(f(b, item))) {
             Ok(b) => b,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
@@ -242,6 +243,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     {
         match self.try_rfold(init, |b, item| Ok::<B, !>(f(b, item))) {
             Ok(b) => b,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs
index 5a5e7f70854..67b5b91c4d4 100644
--- a/library/alloc/src/collections/vec_deque/iter.rs
+++ b/library/alloc/src/collections/vec_deque/iter.rs
@@ -28,6 +28,20 @@ impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
     }
 }
 
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
+impl<T> Default for Iter<'_, T> {
+    /// Creates an empty `vec_deque::Iter`.
+    ///
+    /// ```
+    /// # use std::collections::vec_deque;
+    /// let iter: vec_deque::Iter<'_, u8> = Default::default();
+    /// assert_eq!(iter.len(), 0);
+    /// ```
+    fn default() -> Self {
+        Iter { i1: Default::default(), i2: Default::default() }
+    }
+}
+
 // FIXME(#26925) Remove in favor of `#[derive(Clone)]`
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for Iter<'_, T> {
diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs
index 5061931afb7..2726e3e4252 100644
--- a/library/alloc/src/collections/vec_deque/iter_mut.rs
+++ b/library/alloc/src/collections/vec_deque/iter_mut.rs
@@ -28,6 +28,20 @@ impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
     }
 }
 
+#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")]
+impl<T> Default for IterMut<'_, T> {
+    /// Creates an empty `vec_deque::IterMut`.
+    ///
+    /// ```
+    /// # use std::collections::vec_deque;
+    /// let iter: vec_deque::IterMut<'_, u8> = Default::default();
+    /// assert_eq!(iter.len(), 0);
+    /// ```
+    fn default() -> Self {
+        IterMut { i1: Default::default(), i2: Default::default() }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Iterator for IterMut<'a, T> {
     type Item = &'a mut T;
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 28b08ef5611..3e44adf73f0 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -138,6 +138,7 @@
 #![feature(maybe_uninit_uninit_array_transpose)]
 #![feature(panic_internals)]
 #![feature(pattern)]
+#![feature(pin_coerce_unsized_trait)]
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index bc0874fc13f..bdee06154fa 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -256,6 +256,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Rece
 use core::panic::{RefUnwindSafe, UnwindSafe};
 #[cfg(not(no_global_oom_handling))]
 use core::pin::Pin;
+use core::pin::PinCoerceUnsized;
 use core::ptr::{self, drop_in_place, NonNull};
 #[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
@@ -1372,6 +1373,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
     /// assert_eq!(&*x, "hello");
     /// ```
+    #[must_use = "losing the pointer will leak memory"]
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
         let this = mem::ManuallyDrop::new(this);
@@ -2176,6 +2178,12 @@ impl<T: ?Sized, A: Allocator> Deref for Rc<T, A> {
     }
 }
 
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Rc<T, A> {}
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Weak<T, A> {}
+
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {}
 
@@ -3107,6 +3115,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
     ///
     /// [`from_raw_in`]: Weak::from_raw_in
     /// [`as_ptr`]: Weak::as_ptr
+    #[must_use = "losing the pointer will leak memory"]
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn into_raw_with_allocator(self) -> (*const T, A) {
@@ -3689,6 +3698,9 @@ impl<T: ?Sized, A: Allocator> Deref for UniqueRc<T, A> {
     }
 }
 
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for UniqueRc<T> {}
+
 #[unstable(feature = "unique_rc_arc", issue = "112566")]
 impl<T: ?Sized, A: Allocator> DerefMut for UniqueRc<T, A> {
     fn deref_mut(&mut self) -> &mut T {
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 7dcf344cdc5..9d704870326 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -178,15 +178,25 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
     ///
-    /// If `T: Ord` does not implement a total order the resulting order is unspecified. All
-    /// original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `T: Ord` panics.
+    /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `T` panics.
     ///
     /// When applicable, unstable sorting is preferred because it is generally faster than stable
     /// sorting and it doesn't allocate auxiliary memory. See
     /// [`sort_unstable`](slice::sort_unstable). The exception are partially sorted slices, which
     /// may be better served with `slice::sort`.
     ///
+    /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require
+    /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the
+    /// reflexivity requirement of [`Ord`]. By using an alternative comparison function with
+    /// `slice::sort_by` such as [`f32::total_cmp`] or [`f64::total_cmp`] that defines a [total
+    /// order] users can sort slices containing floating-point values. Alternatively, if all values
+    /// in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`] forms a
+    /// [total order], it's possible to sort the slice with `sort_by(|a, b|
+    /// a.partial_cmp(b).unwrap())`.
+    ///
     /// # Current implementation
     ///
     /// The current implementation is based on [driftsort] by Orson Peters and Lukas Bergdoll, which
@@ -198,18 +208,21 @@ impl<T> [T] {
     /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it
     /// clamps at `self.len() / 2`.
     ///
-    /// If `T: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5, 4, 1, -3, 2];
+    /// let mut v = [4, -5, 1, -3, 2];
     ///
     /// v.sort();
-    /// assert!(v == [-5, -3, 1, 2, 4]);
+    /// assert_eq!(v, [-5, -3, 1, 2, 4]);
     /// ```
     ///
     /// [driftsort]: https://github.com/Voultapher/driftsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -221,30 +234,19 @@ impl<T> [T] {
         stable_sort(self, T::lt);
     }
 
-    /// Sorts the slice with a comparator function, preserving initial order of equal elements.
+    /// Sorts the slice with a comparison function, preserving initial order of equal elements.
     ///
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
     ///
-    /// The comparator function should define a total ordering for the elements in the slice. If the
-    /// ordering is not total, the order of the elements is unspecified.
-    ///
-    /// If the comparator function does not implement a total order the resulting order is
-    /// unspecified. All original elements will remain in the slice and any possible modifications
-    /// via interior mutability are observed in the input. Same is true if the comparator function
-    /// panics. A total order (for all `a`, `b` and `c`):
+    /// If the comparison function `compare` does not implement a [total order] the resulting order
+    /// of elements in the slice is unspecified. All original elements will remain in the slice and
+    /// any possible modifications via interior mutability are observed in the input. Same is true
+    /// if `compare` panics.
     ///
-    /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
-    /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
-    ///
-    /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
-    /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`.
-    ///
-    /// ```
-    /// let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0];
-    /// floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
-    /// assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]);
-    /// ```
+    /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
+    /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
+    /// examples see the [`Ord`] documentation.
     ///
     /// # Current implementation
     ///
@@ -257,21 +259,24 @@ impl<T> [T] {
     /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it
     /// clamps at `self.len() / 2`.
     ///
-    /// If `T: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if `compare` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [5, 4, 1, 3, 2];
+    /// let mut v = [4, -5, 1, -3, 2];
     /// v.sort_by(|a, b| a.cmp(b));
-    /// assert!(v == [1, 2, 3, 4, 5]);
+    /// assert_eq!(v, [-5, -3, 1, 2, 4]);
     ///
     /// // reverse sorting
     /// v.sort_by(|a, b| b.cmp(a));
-    /// assert!(v == [5, 4, 3, 2, 1]);
+    /// assert_eq!(v, [4, 2, 1, -3, -5]);
     /// ```
     ///
     /// [driftsort]: https://github.com/Voultapher/driftsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -288,9 +293,10 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*))
     /// worst-case, where the key function is *O*(*m*).
     ///
-    /// If `K: Ord` does not implement a total order the resulting order is unspecified.
-    /// All original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `K: Ord` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `K` panics.
     ///
     /// # Current implementation
     ///
@@ -303,18 +309,21 @@ impl<T> [T] {
     /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it
     /// clamps at `self.len() / 2`.
     ///
-    /// If `K: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5i32, 4, 1, -3, 2];
+    /// let mut v = [4i32, -5, 1, -3, 2];
     ///
     /// v.sort_by_key(|k| k.abs());
-    /// assert!(v == [1, 2, -3, 4, -5]);
+    /// assert_eq!(v, [1, 2, -3, 4, -5]);
     /// ```
     ///
     /// [driftsort]: https://github.com/Voultapher/driftsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "slice_sort_by_key", since = "1.7.0")]
@@ -336,9 +345,10 @@ impl<T> [T] {
     /// storage to remember the results of key evaluation. The order of calls to the key function is
     /// unspecified and may change in future versions of the standard library.
     ///
-    /// If `K: Ord` does not implement a total order the resulting order is unspecified.
-    /// All original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `K: Ord` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `K` panics.
     ///
     /// For simple key functions (e.g., functions that are property accesses or basic operations),
     /// [`sort_by_key`](slice::sort_by_key) is likely to be faster.
@@ -355,16 +365,22 @@ impl<T> [T] {
     /// In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the
     /// length of the slice.
     ///
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
+    ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5i32, 4, 32, -3, 2];
+    /// let mut v = [4i32, -5, 1, -3, 2, 10];
     ///
+    /// // Strings are sorted by lexicographical order.
     /// v.sort_by_cached_key(|k| k.to_string());
-    /// assert!(v == [-3, -5, 2, 32, 4]);
+    /// assert_eq!(v, [-3, -5, 1, 10, 2, 4]);
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "slice_sort_by_cached_key", since = "1.34.0")]
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 01fe950cf3f..124230812df 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -900,7 +900,7 @@ impl String {
     /// let rebuilt = unsafe { String::from_raw_parts(ptr, len, cap) };
     /// assert_eq!(rebuilt, "hello");
     /// ```
-    #[must_use = "`self` will be dropped if the result is not used"]
+    #[must_use = "losing the pointer will leak memory"]
     #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
     pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
         self.vec.into_raw_parts()
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 3ad0dae77db..2c0d19b0ada 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -20,7 +20,7 @@ use core::marker::{PhantomData, Unsize};
 use core::mem::{self, align_of_val_raw, ManuallyDrop};
 use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver};
 use core::panic::{RefUnwindSafe, UnwindSafe};
-use core::pin::Pin;
+use core::pin::{Pin, PinCoerceUnsized};
 use core::ptr::{self, NonNull};
 #[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
@@ -2142,6 +2142,12 @@ impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
     }
 }
 
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Arc<T, A> {}
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Weak<T, A> {}
+
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {}
 
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index dfd22204c81..b4e0bc5fcbe 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -878,6 +878,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// };
     /// assert_eq!(rebuilt, [4294967295, 0, 1]);
     /// ```
+    #[must_use = "losing the pointer will leak memory"]
     #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
     pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
         let mut me = ManuallyDrop::new(self);
@@ -921,6 +922,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// };
     /// assert_eq!(rebuilt, [4294967295, 0, 1]);
     /// ```
+    #[must_use = "losing the pointer will leak memory"]
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
     pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) {
diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs
index c37a80dca95..dc27c578b57 100644
--- a/library/alloc/tests/arc.rs
+++ b/library/alloc/tests/arc.rs
@@ -227,3 +227,17 @@ fn make_mut_unsized() {
     assert_eq!(*data, [11, 21, 31]);
     assert_eq!(*other_data, [110, 20, 30]);
 }
+
+#[allow(unused)]
+mod pin_coerce_unsized {
+    use alloc::sync::Arc;
+    use core::pin::Pin;
+
+    pub trait MyTrait {}
+    impl MyTrait for String {}
+
+    // Pin coercion should work for Arc
+    pub fn pin_arc(arg: Pin<Arc<String>>) -> Pin<Arc<dyn MyTrait>> {
+        arg
+    }
+}
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index 4cacee0414d..faee64b2f67 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -179,3 +179,40 @@ unsafe impl Allocator for ConstAllocator {
         self
     }
 }
+
+#[allow(unused)]
+mod pin_coerce_unsized {
+    use alloc::boxed::Box;
+    use core::pin::Pin;
+
+    trait MyTrait {
+        fn action(&self) -> &str;
+    }
+    impl MyTrait for String {
+        fn action(&self) -> &str {
+            &*self
+        }
+    }
+    struct MyStruct;
+    impl MyTrait for MyStruct {
+        fn action(&self) -> &str {
+            "MyStruct"
+        }
+    }
+
+    // Pin coercion should work for Box
+    fn pin_box<T: MyTrait + 'static>(arg: Pin<Box<T>>) -> Pin<Box<dyn MyTrait>> {
+        arg
+    }
+
+    #[test]
+    fn pin_coerce_unsized_box() {
+        let my_string = "my string";
+        let a_string = Box::pin(String::from(my_string));
+        let pin_box_str = pin_box(a_string);
+        assert_eq!(pin_box_str.as_ref().action(), my_string);
+        let a_struct = Box::pin(MyStruct);
+        let pin_box_struct = pin_box(a_struct);
+        assert_eq!(pin_box_struct.as_ref().action(), "MyStruct");
+    }
+}
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 89538f272f0..3d4add6fae4 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -40,6 +40,7 @@
 #![feature(drain_keep_rest)]
 #![feature(local_waker)]
 #![feature(vec_pop_if)]
+#![feature(unique_rc_arc)]
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs
index 499740e738a..29dbdcf225e 100644
--- a/library/alloc/tests/rc.rs
+++ b/library/alloc/tests/rc.rs
@@ -205,3 +205,20 @@ fn weak_may_dangle() {
     // `val` dropped here while still borrowed
     // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
 }
+
+#[allow(unused)]
+mod pin_coerce_unsized {
+    use alloc::rc::{Rc, UniqueRc};
+    use core::pin::Pin;
+
+    pub trait MyTrait {}
+    impl MyTrait for String {}
+
+    // Pin coercion should work for Rc
+    pub fn pin_rc(arg: Pin<Rc<String>>) -> Pin<Rc<dyn MyTrait>> {
+        arg
+    }
+    pub fn pin_unique_rc(arg: Pin<UniqueRc<String>>) -> Pin<UniqueRc<dyn MyTrait>> {
+        arg
+    }
+}
diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs
index 31d6bc36fc8..d681bd124fe 100644
--- a/library/core/src/arch.rs
+++ b/library/core/src/arch.rs
@@ -4,6 +4,15 @@
 #[stable(feature = "simd_arch", since = "1.27.0")]
 pub use crate::core_arch::arch::*;
 
+#[cfg(bootstrap)]
+#[allow(dead_code)]
+#[unstable(feature = "sha512_sm_x86", issue = "126624")]
+fn dummy() {
+    // AArch64 also has a target feature named `sm4`, so we need `#![feature(sha512_sm_x86)]` in lib.rs
+    // But as the bootstrap compiler doesn't know about this feature yet, we need to convert it to a
+    // library feature until bootstrap gets bumped
+}
+
 /// Inline assembly.
 ///
 /// Refer to [Rust By Example] for a usage guide and the [reference] for
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 0d66c2b52c8..d860f3415d9 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -255,6 +255,7 @@ use crate::fmt::{self, Debug, Display};
 use crate::marker::{PhantomData, Unsize};
 use crate::mem;
 use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
+use crate::pin::PinCoerceUnsized;
 use crate::ptr::{self, NonNull};
 
 mod lazy;
@@ -2396,3 +2397,21 @@ fn assert_coerce_unsized(
     let _: Cell<&dyn Send> = c;
     let _: RefCell<&dyn Send> = d;
 }
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for UnsafeCell<T> {}
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for SyncUnsafeCell<T> {}
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for Cell<T> {}
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for RefCell<T> {}
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<'b, T: ?Sized> PinCoerceUnsized for Ref<'b, T> {}
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<'b, T: ?Sized> PinCoerceUnsized for RefMut<'b, T> {}
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index 4524b352ec8..5cacedcb241 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -103,6 +103,7 @@ use crate::ascii::Char as AsciiChar;
 /// ```
 #[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
 pub trait Default: Sized {
     /// Returns the "default value" for a type.
     ///
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index e9eacbcd25a..6f1e0cb7471 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1528,6 +1528,12 @@ extern "rust-intrinsic" {
     #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"]
     pub fn unaligned_volatile_store<T>(dst: *mut T, val: T);
 
+    /// Returns the square root of an `f16`
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt)
+    #[rustc_nounwind]
+    pub fn sqrtf16(x: f16) -> f16;
     /// Returns the square root of an `f32`
     ///
     /// The stabilized version of this intrinsic is
@@ -1540,6 +1546,12 @@ extern "rust-intrinsic" {
     /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt)
     #[rustc_nounwind]
     pub fn sqrtf64(x: f64) -> f64;
+    /// Returns the square root of an `f128`
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt)
+    #[rustc_nounwind]
+    pub fn sqrtf128(x: f128) -> f128;
 
     /// Raises an `f16` to an integer power.
     ///
@@ -1566,6 +1578,12 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn powif128(a: f128, x: i32) -> f128;
 
+    /// Returns the sine of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::sin`](../../std/primitive.f16.html#method.sin)
+    #[rustc_nounwind]
+    pub fn sinf16(x: f16) -> f16;
     /// Returns the sine of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1578,7 +1596,19 @@ extern "rust-intrinsic" {
     /// [`f64::sin`](../../std/primitive.f64.html#method.sin)
     #[rustc_nounwind]
     pub fn sinf64(x: f64) -> f64;
+    /// Returns the sine of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::sin`](../../std/primitive.f128.html#method.sin)
+    #[rustc_nounwind]
+    pub fn sinf128(x: f128) -> f128;
 
+    /// Returns the cosine of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::cos`](../../std/primitive.f16.html#method.cos)
+    #[rustc_nounwind]
+    pub fn cosf16(x: f16) -> f16;
     /// Returns the cosine of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1591,7 +1621,19 @@ extern "rust-intrinsic" {
     /// [`f64::cos`](../../std/primitive.f64.html#method.cos)
     #[rustc_nounwind]
     pub fn cosf64(x: f64) -> f64;
+    /// Returns the cosine of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::cos`](../../std/primitive.f128.html#method.cos)
+    #[rustc_nounwind]
+    pub fn cosf128(x: f128) -> f128;
 
+    /// Raises an `f16` to an `f16` power.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::powf`](../../std/primitive.f16.html#method.powf)
+    #[rustc_nounwind]
+    pub fn powf16(a: f16, x: f16) -> f16;
     /// Raises an `f32` to an `f32` power.
     ///
     /// The stabilized version of this intrinsic is
@@ -1604,7 +1646,19 @@ extern "rust-intrinsic" {
     /// [`f64::powf`](../../std/primitive.f64.html#method.powf)
     #[rustc_nounwind]
     pub fn powf64(a: f64, x: f64) -> f64;
+    /// Raises an `f128` to an `f128` power.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::powf`](../../std/primitive.f128.html#method.powf)
+    #[rustc_nounwind]
+    pub fn powf128(a: f128, x: f128) -> f128;
 
+    /// Returns the exponential of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::exp`](../../std/primitive.f16.html#method.exp)
+    #[rustc_nounwind]
+    pub fn expf16(x: f16) -> f16;
     /// Returns the exponential of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1617,7 +1671,19 @@ extern "rust-intrinsic" {
     /// [`f64::exp`](../../std/primitive.f64.html#method.exp)
     #[rustc_nounwind]
     pub fn expf64(x: f64) -> f64;
+    /// Returns the exponential of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::exp`](../../std/primitive.f128.html#method.exp)
+    #[rustc_nounwind]
+    pub fn expf128(x: f128) -> f128;
 
+    /// Returns 2 raised to the power of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2)
+    #[rustc_nounwind]
+    pub fn exp2f16(x: f16) -> f16;
     /// Returns 2 raised to the power of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1630,7 +1696,19 @@ extern "rust-intrinsic" {
     /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2)
     #[rustc_nounwind]
     pub fn exp2f64(x: f64) -> f64;
+    /// Returns 2 raised to the power of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2)
+    #[rustc_nounwind]
+    pub fn exp2f128(x: f128) -> f128;
 
+    /// Returns the natural logarithm of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::ln`](../../std/primitive.f16.html#method.ln)
+    #[rustc_nounwind]
+    pub fn logf16(x: f16) -> f16;
     /// Returns the natural logarithm of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1643,7 +1721,19 @@ extern "rust-intrinsic" {
     /// [`f64::ln`](../../std/primitive.f64.html#method.ln)
     #[rustc_nounwind]
     pub fn logf64(x: f64) -> f64;
+    /// Returns the natural logarithm of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::ln`](../../std/primitive.f128.html#method.ln)
+    #[rustc_nounwind]
+    pub fn logf128(x: f128) -> f128;
 
+    /// Returns the base 10 logarithm of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::log10`](../../std/primitive.f16.html#method.log10)
+    #[rustc_nounwind]
+    pub fn log10f16(x: f16) -> f16;
     /// Returns the base 10 logarithm of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1656,7 +1746,19 @@ extern "rust-intrinsic" {
     /// [`f64::log10`](../../std/primitive.f64.html#method.log10)
     #[rustc_nounwind]
     pub fn log10f64(x: f64) -> f64;
+    /// Returns the base 10 logarithm of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::log10`](../../std/primitive.f128.html#method.log10)
+    #[rustc_nounwind]
+    pub fn log10f128(x: f128) -> f128;
 
+    /// Returns the base 2 logarithm of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::log2`](../../std/primitive.f16.html#method.log2)
+    #[rustc_nounwind]
+    pub fn log2f16(x: f16) -> f16;
     /// Returns the base 2 logarithm of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1669,7 +1771,19 @@ extern "rust-intrinsic" {
     /// [`f64::log2`](../../std/primitive.f64.html#method.log2)
     #[rustc_nounwind]
     pub fn log2f64(x: f64) -> f64;
+    /// Returns the base 2 logarithm of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::log2`](../../std/primitive.f128.html#method.log2)
+    #[rustc_nounwind]
+    pub fn log2f128(x: f128) -> f128;
 
+    /// Returns `a * b + c` for `f16` values.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add)
+    #[rustc_nounwind]
+    pub fn fmaf16(a: f16, b: f16, c: f16) -> f16;
     /// Returns `a * b + c` for `f32` values.
     ///
     /// The stabilized version of this intrinsic is
@@ -1682,7 +1796,19 @@ extern "rust-intrinsic" {
     /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add)
     #[rustc_nounwind]
     pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;
+    /// Returns `a * b + c` for `f128` values.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add)
+    #[rustc_nounwind]
+    pub fn fmaf128(a: f128, b: f128, c: f128) -> f128;
 
+    /// Returns the absolute value of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::abs`](../../std/primitive.f16.html#method.abs)
+    #[rustc_nounwind]
+    pub fn fabsf16(x: f16) -> f16;
     /// Returns the absolute value of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1695,7 +1821,25 @@ extern "rust-intrinsic" {
     /// [`f64::abs`](../../std/primitive.f64.html#method.abs)
     #[rustc_nounwind]
     pub fn fabsf64(x: f64) -> f64;
+    /// Returns the absolute value of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::abs`](../../std/primitive.f128.html#method.abs)
+    #[rustc_nounwind]
+    pub fn fabsf128(x: f128) -> f128;
 
+    /// Returns the minimum of two `f16` values.
+    ///
+    /// Note that, unlike most intrinsics, this is safe to call;
+    /// it does not require an `unsafe` block.
+    /// Therefore, implementations must not require the user to uphold
+    /// any safety invariants.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::min`]
+    #[rustc_safe_intrinsic]
+    #[rustc_nounwind]
+    pub fn minnumf16(x: f16, y: f16) -> f16;
     /// Returns the minimum of two `f32` values.
     ///
     /// Note that, unlike most intrinsics, this is safe to call;
@@ -1720,6 +1864,31 @@ extern "rust-intrinsic" {
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn minnumf64(x: f64, y: f64) -> f64;
+    /// Returns the minimum of two `f128` values.
+    ///
+    /// Note that, unlike most intrinsics, this is safe to call;
+    /// it does not require an `unsafe` block.
+    /// Therefore, implementations must not require the user to uphold
+    /// any safety invariants.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::min`]
+    #[rustc_safe_intrinsic]
+    #[rustc_nounwind]
+    pub fn minnumf128(x: f128, y: f128) -> f128;
+
+    /// Returns the maximum of two `f16` values.
+    ///
+    /// Note that, unlike most intrinsics, this is safe to call;
+    /// it does not require an `unsafe` block.
+    /// Therefore, implementations must not require the user to uphold
+    /// any safety invariants.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::max`]
+    #[rustc_safe_intrinsic]
+    #[rustc_nounwind]
+    pub fn maxnumf16(x: f16, y: f16) -> f16;
     /// Returns the maximum of two `f32` values.
     ///
     /// Note that, unlike most intrinsics, this is safe to call;
@@ -1744,7 +1913,25 @@ extern "rust-intrinsic" {
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
     pub fn maxnumf64(x: f64, y: f64) -> f64;
+    /// Returns the maximum of two `f128` values.
+    ///
+    /// Note that, unlike most intrinsics, this is safe to call;
+    /// it does not require an `unsafe` block.
+    /// Therefore, implementations must not require the user to uphold
+    /// any safety invariants.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::max`]
+    #[rustc_safe_intrinsic]
+    #[rustc_nounwind]
+    pub fn maxnumf128(x: f128, y: f128) -> f128;
 
+    /// Copies the sign from `y` to `x` for `f16` values.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign)
+    #[rustc_nounwind]
+    pub fn copysignf16(x: f16, y: f16) -> f16;
     /// Copies the sign from `y` to `x` for `f32` values.
     ///
     /// The stabilized version of this intrinsic is
@@ -1757,7 +1944,19 @@ extern "rust-intrinsic" {
     /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign)
     #[rustc_nounwind]
     pub fn copysignf64(x: f64, y: f64) -> f64;
+    /// Copies the sign from `y` to `x` for `f128` values.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign)
+    #[rustc_nounwind]
+    pub fn copysignf128(x: f128, y: f128) -> f128;
 
+    /// Returns the largest integer less than or equal to an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::floor`](../../std/primitive.f16.html#method.floor)
+    #[rustc_nounwind]
+    pub fn floorf16(x: f16) -> f16;
     /// Returns the largest integer less than or equal to an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1770,7 +1969,19 @@ extern "rust-intrinsic" {
     /// [`f64::floor`](../../std/primitive.f64.html#method.floor)
     #[rustc_nounwind]
     pub fn floorf64(x: f64) -> f64;
+    /// Returns the largest integer less than or equal to an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::floor`](../../std/primitive.f128.html#method.floor)
+    #[rustc_nounwind]
+    pub fn floorf128(x: f128) -> f128;
 
+    /// Returns the smallest integer greater than or equal to an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil)
+    #[rustc_nounwind]
+    pub fn ceilf16(x: f16) -> f16;
     /// Returns the smallest integer greater than or equal to an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1783,7 +1994,19 @@ extern "rust-intrinsic" {
     /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil)
     #[rustc_nounwind]
     pub fn ceilf64(x: f64) -> f64;
+    /// Returns the smallest integer greater than or equal to an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil)
+    #[rustc_nounwind]
+    pub fn ceilf128(x: f128) -> f128;
 
+    /// Returns the integer part of an `f16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc)
+    #[rustc_nounwind]
+    pub fn truncf16(x: f16) -> f16;
     /// Returns the integer part of an `f32`.
     ///
     /// The stabilized version of this intrinsic is
@@ -1796,7 +2019,25 @@ extern "rust-intrinsic" {
     /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc)
     #[rustc_nounwind]
     pub fn truncf64(x: f64) -> f64;
+    /// Returns the integer part of an `f128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc)
+    #[rustc_nounwind]
+    pub fn truncf128(x: f128) -> f128;
 
+    /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust,
+    /// so this rounds half-way cases to the number with an even least significant digit.
+    ///
+    /// May raise an inexact floating-point exception if the argument is not an integer.
+    /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions
+    /// cannot actually be utilized from Rust code.
+    /// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even)
+    #[rustc_nounwind]
+    pub fn rintf16(x: f16) -> f16;
     /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust,
     /// so this rounds half-way cases to the number with an even least significant digit.
     ///
@@ -1821,7 +2062,25 @@ extern "rust-intrinsic" {
     /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
     #[rustc_nounwind]
     pub fn rintf64(x: f64) -> f64;
+    /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust,
+    /// so this rounds half-way cases to the number with an even least significant digit.
+    ///
+    /// May raise an inexact floating-point exception if the argument is not an integer.
+    /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions
+    /// cannot actually be utilized from Rust code.
+    /// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even)
+    #[rustc_nounwind]
+    pub fn rintf128(x: f128) -> f128;
 
+    /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust,
+    /// so this rounds half-way cases to the number with an even least significant digit.
+    ///
+    /// This intrinsic does not have a stable counterpart.
+    #[rustc_nounwind]
+    pub fn nearbyintf16(x: f16) -> f16;
     /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust,
     /// so this rounds half-way cases to the number with an even least significant digit.
     ///
@@ -1834,7 +2093,19 @@ extern "rust-intrinsic" {
     /// This intrinsic does not have a stable counterpart.
     #[rustc_nounwind]
     pub fn nearbyintf64(x: f64) -> f64;
+    /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust,
+    /// so this rounds half-way cases to the number with an even least significant digit.
+    ///
+    /// This intrinsic does not have a stable counterpart.
+    #[rustc_nounwind]
+    pub fn nearbyintf128(x: f128) -> f128;
 
+    /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::round`](../../std/primitive.f16.html#method.round)
+    #[rustc_nounwind]
+    pub fn roundf16(x: f16) -> f16;
     /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero.
     ///
     /// The stabilized version of this intrinsic is
@@ -1847,7 +2118,19 @@ extern "rust-intrinsic" {
     /// [`f64::round`](../../std/primitive.f64.html#method.round)
     #[rustc_nounwind]
     pub fn roundf64(x: f64) -> f64;
+    /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::round`](../../std/primitive.f128.html#method.round)
+    #[rustc_nounwind]
+    pub fn roundf128(x: f128) -> f128;
 
+    /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// This intrinsic does not have a stable counterpart.
+    #[rustc_nounwind]
+    pub fn roundevenf16(x: f16) -> f16;
     /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number
     /// with an even least significant digit.
     ///
@@ -1860,6 +2143,12 @@ extern "rust-intrinsic" {
     /// This intrinsic does not have a stable counterpart.
     #[rustc_nounwind]
     pub fn roundevenf64(x: f64) -> f64;
+    /// Returns the nearest integer to an `f128`. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// This intrinsic does not have a stable counterpart.
+    #[rustc_nounwind]
+    pub fn roundevenf128(x: f128) -> f128;
 
     /// Float addition that allows optimizations based on algebraic rules.
     /// May assume inputs are finite.
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index fd49a96eaa0..c7cec396e1f 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -247,6 +247,8 @@
 //!       otherwise branch.
 //!  - [`Call`] has an associated function as well, with special syntax:
 //!    `Call(ret_val = function(arg1, arg2, ...), ReturnTo(next_block), UnwindContinue())`.
+//!  - [`TailCall`] does not have a return destination or next block, so its syntax is just
+//!    `TailCall(function(arg1, arg2, ...))`.
 
 #![unstable(
     feature = "custom_mir",
@@ -350,6 +352,12 @@ define!("mir_call",
     /// - [`UnwindCleanup`]
     fn Call(call: (), goto: ReturnToArg, unwind_action: UnwindActionArg)
 );
+define!("mir_tail_call",
+    /// Call a function.
+    ///
+    /// The argument must be of the form `fun(arg1, arg2, ...)`.
+    fn TailCall<T>(call: T)
+);
 define!("mir_unwind_resume",
     /// A terminator that resumes the unwinding.
     fn UnwindResume()
diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs
index 8390dab8e54..4c4ae39f836 100644
--- a/library/core/src/iter/sources/repeat_n.rs
+++ b/library/core/src/iter/sources/repeat_n.rs
@@ -114,19 +114,12 @@ impl<A: Clone> Iterator for RepeatN<A> {
 
     #[inline]
     fn next(&mut self) -> Option<A> {
-        if self.count == 0 {
-            return None;
-        }
-
-        self.count -= 1;
-        Some(if self.count == 0 {
-            // SAFETY: the check above ensured that the count used to be non-zero,
-            // so element hasn't been dropped yet, and we just lowered the count to
-            // zero so it won't be dropped later, and thus it's okay to take it here.
-            unsafe { ManuallyDrop::take(&mut self.element) }
+        if self.count > 0 {
+            // SAFETY: Just checked it's not empty
+            unsafe { Some(self.next_unchecked()) }
         } else {
-            A::clone(&self.element)
-        })
+            None
+        }
     }
 
     #[inline]
@@ -194,4 +187,18 @@ impl<A: Clone> FusedIterator for RepeatN<A> {}
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<A: Clone> TrustedLen for RepeatN<A> {}
 #[unstable(feature = "trusted_len_next_unchecked", issue = "37572")]
-impl<A: Clone> UncheckedIterator for RepeatN<A> {}
+impl<A: Clone> UncheckedIterator for RepeatN<A> {
+    #[inline]
+    unsafe fn next_unchecked(&mut self) -> Self::Item {
+        // SAFETY: The caller promised the iterator isn't empty
+        self.count = unsafe { self.count.unchecked_sub(1) };
+        if self.count == 0 {
+            // SAFETY: the check above ensured that the count used to be non-zero,
+            // so element hasn't been dropped yet, and we just lowered the count to
+            // zero so it won't be dropped later, and thus it's okay to take it here.
+            unsafe { ManuallyDrop::take(&mut self.element) }
+        } else {
+            A::clone(&self.element)
+        }
+    }
+}
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 0917631e045..07daa32afa8 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -192,6 +192,7 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
@@ -225,7 +226,6 @@
 #![feature(link_llvm_intrinsics)]
 #![feature(macro_metavar_expr)]
 #![feature(marker_trait_attr)]
-#![feature(min_exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(multiple_supertrait_upcastable)]
 #![feature(must_not_suspend)]
@@ -260,9 +260,11 @@
 #![feature(powerpc_target_feature)]
 #![feature(riscv_target_feature)]
 #![feature(rtm_target_feature)]
+#![feature(sha512_sm_x86)]
 #![feature(sse4a_target_feature)]
 #![feature(tbm_target_feature)]
 #![feature(wasm_target_feature)]
+#![feature(x86_amx_intrinsics)]
 // tidy-alphabetical-end
 
 // allow using `core::` in intra-doc links
@@ -389,7 +391,7 @@ pub mod net;
 pub mod option;
 pub mod panic;
 pub mod panicking;
-#[unstable(feature = "core_pattern_types", issue = "none")]
+#[unstable(feature = "core_pattern_types", issue = "123646")]
 pub mod pat;
 pub mod pin;
 #[unstable(feature = "new_range_api", issue = "125687")]
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 6a24748fd9e..0c04f47fe7d 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -686,6 +686,182 @@ impl f128 {
         self * RADS_PER_DEG
     }
 
+    /// Returns the maximum of the two numbers, ignoring NaN.
+    ///
+    /// If one of the arguments is NaN, then the other argument is returned.
+    /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
+    /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
+    /// This also matches the behavior of libm’s fmax.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # // Using aarch64 because `reliable_f128_math` is needed
+    /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
+    ///
+    /// let x = 1.0f128;
+    /// let y = 2.0f128;
+    ///
+    /// assert_eq!(x.max(y), y);
+    /// # }
+    /// ```
+    #[inline]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
+    pub fn max(self, other: f128) -> f128 {
+        intrinsics::maxnumf128(self, other)
+    }
+
+    /// Returns the minimum of the two numbers, ignoring NaN.
+    ///
+    /// If one of the arguments is NaN, then the other argument is returned.
+    /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
+    /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
+    /// This also matches the behavior of libm’s fmin.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # // Using aarch64 because `reliable_f128_math` is needed
+    /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
+    ///
+    /// let x = 1.0f128;
+    /// let y = 2.0f128;
+    ///
+    /// assert_eq!(x.min(y), x);
+    /// # }
+    /// ```
+    #[inline]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
+    pub fn min(self, other: f128) -> f128 {
+        intrinsics::minnumf128(self, other)
+    }
+
+    /// Returns the maximum of the two numbers, propagating NaN.
+    ///
+    /// This returns NaN when *either* argument is NaN, as opposed to
+    /// [`f128::max`] which only returns NaN when *both* arguments are NaN.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// #![feature(float_minimum_maximum)]
+    /// # // Using aarch64 because `reliable_f128_math` is needed
+    /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
+    ///
+    /// let x = 1.0f128;
+    /// let y = 2.0f128;
+    ///
+    /// assert_eq!(x.maximum(y), y);
+    /// assert!(x.maximum(f128::NAN).is_nan());
+    /// # }
+    /// ```
+    ///
+    /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
+    /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
+    /// Note that this follows the semantics specified in IEEE 754-2019.
+    ///
+    /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+    /// operand is conserved; see [explanation of NaN as a special value](f128) for more info.
+    #[inline]
+    #[unstable(feature = "f128", issue = "116909")]
+    // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
+    pub fn maximum(self, other: f128) -> f128 {
+        if self > other {
+            self
+        } else if other > self {
+            other
+        } else if self == other {
+            if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
+        } else {
+            self + other
+        }
+    }
+
+    /// Returns the minimum of the two numbers, propagating NaN.
+    ///
+    /// This returns NaN when *either* argument is NaN, as opposed to
+    /// [`f128::min`] which only returns NaN when *both* arguments are NaN.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// #![feature(float_minimum_maximum)]
+    /// # // Using aarch64 because `reliable_f128_math` is needed
+    /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
+    ///
+    /// let x = 1.0f128;
+    /// let y = 2.0f128;
+    ///
+    /// assert_eq!(x.minimum(y), x);
+    /// assert!(x.minimum(f128::NAN).is_nan());
+    /// # }
+    /// ```
+    ///
+    /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
+    /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
+    /// Note that this follows the semantics specified in IEEE 754-2019.
+    ///
+    /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+    /// operand is conserved; see [explanation of NaN as a special value](f128) for more info.
+    #[inline]
+    #[unstable(feature = "f128", issue = "116909")]
+    // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
+    pub fn minimum(self, other: f128) -> f128 {
+        if self < other {
+            self
+        } else if other < self {
+            other
+        } else if self == other {
+            if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
+        } else {
+            // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+            self + other
+        }
+    }
+
+    /// Calculates the middle point of `self` and `rhs`.
+    ///
+    /// This returns NaN when *either* argument is NaN or if a combination of
+    /// +inf and -inf is provided as arguments.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// #![feature(num_midpoint)]
+    /// # // Using aarch64 because `reliable_f128_math` is needed
+    /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
+    ///
+    /// assert_eq!(1f128.midpoint(4.0), 2.5);
+    /// assert_eq!((-5.5f128).midpoint(8.0), 1.25);
+    /// # }
+    /// ```
+    #[inline]
+    #[unstable(feature = "f128", issue = "116909")]
+    // #[unstable(feature = "num_midpoint", issue = "110840")]
+    pub fn midpoint(self, other: f128) -> f128 {
+        const LO: f128 = f128::MIN_POSITIVE * 2.;
+        const HI: f128 = f128::MAX / 2.;
+
+        let (a, b) = (self, other);
+        let abs_a = a.abs_private();
+        let abs_b = b.abs_private();
+
+        if abs_a <= HI && abs_b <= HI {
+            // Overflow is impossible
+            (a + b) / 2.
+        } else if abs_a < LO {
+            // Not safe to halve `a` (would underflow)
+            a + (b / 2.)
+        } else if abs_b < LO {
+            // Not safe to halve `b` (would underflow)
+            (a / 2.) + b
+        } else {
+            // Safe to halve `a` and `b`
+            (a / 2.) + (b / 2.)
+        }
+    }
+
     /// Rounds toward zero and converts to any primitive integer type,
     /// assuming that the value is finite and fits in that type.
     ///
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 054897b3c96..e5b1148e192 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -720,6 +720,177 @@ impl f16 {
         self * RADS_PER_DEG
     }
 
+    /// Returns the maximum of the two numbers, ignoring NaN.
+    ///
+    /// If one of the arguments is NaN, then the other argument is returned.
+    /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
+    /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
+    /// This also matches the behavior of libm’s fmax.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
+    ///
+    /// let x = 1.0f16;
+    /// let y = 2.0f16;
+    ///
+    /// assert_eq!(x.max(y), y);
+    /// # }
+    /// ```
+    #[inline]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
+    pub fn max(self, other: f16) -> f16 {
+        intrinsics::maxnumf16(self, other)
+    }
+
+    /// Returns the minimum of the two numbers, ignoring NaN.
+    ///
+    /// If one of the arguments is NaN, then the other argument is returned.
+    /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
+    /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
+    /// This also matches the behavior of libm’s fmin.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
+    ///
+    /// let x = 1.0f16;
+    /// let y = 2.0f16;
+    ///
+    /// assert_eq!(x.min(y), x);
+    /// # }
+    /// ```
+    #[inline]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
+    pub fn min(self, other: f16) -> f16 {
+        intrinsics::minnumf16(self, other)
+    }
+
+    /// Returns the maximum of the two numbers, propagating NaN.
+    ///
+    /// This returns NaN when *either* argument is NaN, as opposed to
+    /// [`f16::max`] which only returns NaN when *both* arguments are NaN.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// #![feature(float_minimum_maximum)]
+    /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
+    ///
+    /// let x = 1.0f16;
+    /// let y = 2.0f16;
+    ///
+    /// assert_eq!(x.maximum(y), y);
+    /// assert!(x.maximum(f16::NAN).is_nan());
+    /// # }
+    /// ```
+    ///
+    /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
+    /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
+    /// Note that this follows the semantics specified in IEEE 754-2019.
+    ///
+    /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+    /// operand is conserved; see [explanation of NaN as a special value](f16) for more info.
+    #[inline]
+    #[unstable(feature = "f16", issue = "116909")]
+    // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
+    pub fn maximum(self, other: f16) -> f16 {
+        if self > other {
+            self
+        } else if other > self {
+            other
+        } else if self == other {
+            if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
+        } else {
+            self + other
+        }
+    }
+
+    /// Returns the minimum of the two numbers, propagating NaN.
+    ///
+    /// This returns NaN when *either* argument is NaN, as opposed to
+    /// [`f16::min`] which only returns NaN when *both* arguments are NaN.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// #![feature(float_minimum_maximum)]
+    /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
+    ///
+    /// let x = 1.0f16;
+    /// let y = 2.0f16;
+    ///
+    /// assert_eq!(x.minimum(y), x);
+    /// assert!(x.minimum(f16::NAN).is_nan());
+    /// # }
+    /// ```
+    ///
+    /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
+    /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
+    /// Note that this follows the semantics specified in IEEE 754-2019.
+    ///
+    /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+    /// operand is conserved; see [explanation of NaN as a special value](f16) for more info.
+    #[inline]
+    #[unstable(feature = "f16", issue = "116909")]
+    // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
+    pub fn minimum(self, other: f16) -> f16 {
+        if self < other {
+            self
+        } else if other < self {
+            other
+        } else if self == other {
+            if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
+        } else {
+            // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
+            self + other
+        }
+    }
+
+    /// Calculates the middle point of `self` and `rhs`.
+    ///
+    /// This returns NaN when *either* argument is NaN or if a combination of
+    /// +inf and -inf is provided as arguments.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// #![feature(num_midpoint)]
+    /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
+    ///
+    /// assert_eq!(1f16.midpoint(4.0), 2.5);
+    /// assert_eq!((-5.5f16).midpoint(8.0), 1.25);
+    /// # }
+    /// ```
+    #[inline]
+    #[unstable(feature = "f16", issue = "116909")]
+    // #[unstable(feature = "num_midpoint", issue = "110840")]
+    pub fn midpoint(self, other: f16) -> f16 {
+        const LO: f16 = f16::MIN_POSITIVE * 2.;
+        const HI: f16 = f16::MAX / 2.;
+
+        let (a, b) = (self, other);
+        let abs_a = a.abs_private();
+        let abs_b = b.abs_private();
+
+        if abs_a <= HI && abs_b <= HI {
+            // Overflow is impossible
+            (a + b) / 2.
+        } else if abs_a < LO {
+            // Not safe to halve `a` (would underflow)
+            a + (b / 2.)
+        } else if abs_b < LO {
+            // Not safe to halve `b` (would underflow)
+            (a / 2.) + b
+        } else {
+            // Safe to halve `a` and `b`
+            (a / 2.) + (b / 2.)
+        }
+    }
+
     /// Rounds toward zero and converts to any primitive integer type,
     /// assuming that the value is finite and fits in that type.
     ///
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 08d863f17ca..7710e23edf0 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -797,6 +797,7 @@ impl f32 {
     /// [`INFINITY`]: Self::INFINITY
     /// [`MIN`]: Self::MIN
     /// [`MAX`]: Self::MAX
+    #[inline]
     #[unstable(feature = "float_next_up_down", issue = "91399")]
     #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
     pub const fn next_up(self) -> Self {
@@ -845,6 +846,7 @@ impl f32 {
     /// [`INFINITY`]: Self::INFINITY
     /// [`MIN`]: Self::MIN
     /// [`MAX`]: Self::MAX
+    #[inline]
     #[unstable(feature = "float_next_up_down", issue = "91399")]
     #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
     pub const fn next_down(self) -> Self {
@@ -1042,6 +1044,7 @@ impl f32 {
     /// assert_eq!(1f32.midpoint(4.0), 2.5);
     /// assert_eq!((-5.5f32).midpoint(8.0), 1.25);
     /// ```
+    #[inline]
     #[unstable(feature = "num_midpoint", issue = "110840")]
     pub fn midpoint(self, other: f32) -> f32 {
         cfg_if! {
@@ -1070,13 +1073,13 @@ impl f32 {
                     // Overflow is impossible
                     (a + b) / 2.
                 } else if abs_a < LO {
-                    // Not safe to halve a
+                    // Not safe to halve `a` (would underflow)
                     a + (b / 2.)
                 } else if abs_b < LO {
-                    // Not safe to halve b
+                    // Not safe to halve `b` (would underflow)
                     (a / 2.) + b
                 } else {
-                    // Not safe to halve a and b
+                    // Safe to halve `a` and `b`
                     (a / 2.) + (b / 2.)
                 }
             }
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 5d33eea6d01..a89859be7ef 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -805,6 +805,7 @@ impl f64 {
     /// [`INFINITY`]: Self::INFINITY
     /// [`MIN`]: Self::MIN
     /// [`MAX`]: Self::MAX
+    #[inline]
     #[unstable(feature = "float_next_up_down", issue = "91399")]
     #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
     pub const fn next_up(self) -> Self {
@@ -853,6 +854,7 @@ impl f64 {
     /// [`INFINITY`]: Self::INFINITY
     /// [`MIN`]: Self::MIN
     /// [`MAX`]: Self::MAX
+    #[inline]
     #[unstable(feature = "float_next_up_down", issue = "91399")]
     #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
     pub const fn next_down(self) -> Self {
@@ -1051,6 +1053,7 @@ impl f64 {
     /// assert_eq!(1f64.midpoint(4.0), 2.5);
     /// assert_eq!((-5.5f64).midpoint(8.0), 1.25);
     /// ```
+    #[inline]
     #[unstable(feature = "num_midpoint", issue = "110840")]
     pub fn midpoint(self, other: f64) -> f64 {
         const LO: f64 = f64::MIN_POSITIVE * 2.;
@@ -1064,13 +1067,13 @@ impl f64 {
             // Overflow is impossible
             (a + b) / 2.
         } else if abs_a < LO {
-            // Not safe to halve a
+            // Not safe to halve `a` (would underflow)
             a + (b / 2.)
         } else if abs_b < LO {
-            // Not safe to halve b
+            // Not safe to halve `b` (would underflow)
             (a / 2.) + b
         } else {
-            // Not safe to halve a and b
+            // Safe to halve `a` and `b`
             (a / 2.) + (b / 2.)
         }
     }
diff --git a/library/core/src/num/flt2dec/strategy/dragon.rs b/library/core/src/num/flt2dec/strategy/dragon.rs
index 751edd3c793..f8db6370653 100644
--- a/library/core/src/num/flt2dec/strategy/dragon.rs
+++ b/library/core/src/num/flt2dec/strategy/dragon.rs
@@ -12,48 +12,51 @@ use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS};
 
 static POW10: [Digit; 10] =
     [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];
-static TWOPOW10: [Digit; 10] =
-    [2, 20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000];
-
-// precalculated arrays of `Digit`s for 10^(2^n)
-static POW10TO16: [Digit; 2] = [0x6fc10000, 0x2386f2];
-static POW10TO32: [Digit; 4] = [0, 0x85acef81, 0x2d6d415b, 0x4ee];
-static POW10TO64: [Digit; 7] = [0, 0, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03];
-static POW10TO128: [Digit; 14] = [
-    0, 0, 0, 0, 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da,
-    0xa6337f19, 0xe91f2603, 0x24e,
+// precalculated arrays of `Digit`s for 5^(2^n).
+static POW5TO16: [Digit; 2] = [0x86f26fc1, 0x23];
+static POW5TO32: [Digit; 3] = [0x85acef81, 0x2d6d415b, 0x4ee];
+static POW5TO64: [Digit; 5] = [0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03];
+static POW5TO128: [Digit; 10] = [
+    0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da, 0xa6337f19,
+    0xe91f2603, 0x24e,
 ];
-static POW10TO256: [Digit; 27] = [
-    0, 0, 0, 0, 0, 0, 0, 0, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70,
-    0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17,
-    0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x553f7,
+static POW5TO256: [Digit; 19] = [
+    0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f, 0x26b2716e,
+    0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7,
+    0xf46eeddc, 0x5fdcefce, 0x553f7,
 ];
 
 #[doc(hidden)]
 pub fn mul_pow10(x: &mut Big, n: usize) -> &mut Big {
     debug_assert!(n < 512);
+    // Save ourself the left shift for the smallest cases.
+    if n < 8 {
+        return x.mul_small(POW10[n & 7]);
+    }
+    // Multiply by the powers of 5 and shift the 2s in at the end.
+    // This keeps the intermediate products smaller and faster.
     if n & 7 != 0 {
-        x.mul_small(POW10[n & 7]);
+        x.mul_small(POW10[n & 7] >> (n & 7));
     }
     if n & 8 != 0 {
-        x.mul_small(POW10[8]);
+        x.mul_small(POW10[8] >> 8);
     }
     if n & 16 != 0 {
-        x.mul_digits(&POW10TO16);
+        x.mul_digits(&POW5TO16);
     }
     if n & 32 != 0 {
-        x.mul_digits(&POW10TO32);
+        x.mul_digits(&POW5TO32);
     }
     if n & 64 != 0 {
-        x.mul_digits(&POW10TO64);
+        x.mul_digits(&POW5TO64);
     }
     if n & 128 != 0 {
-        x.mul_digits(&POW10TO128);
+        x.mul_digits(&POW5TO128);
     }
     if n & 256 != 0 {
-        x.mul_digits(&POW10TO256);
+        x.mul_digits(&POW5TO256);
     }
-    x
+    x.mul_pow2(n)
 }
 
 fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
@@ -62,7 +65,7 @@ fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big {
         x.div_rem_small(POW10[largest]);
         n -= largest;
     }
-    x.div_rem_small(TWOPOW10[n]);
+    x.div_rem_small(POW10[n] << 1);
     x
 }
 
diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs
index a10c4593342..1f89d960be6 100644
--- a/library/core/src/pat.rs
+++ b/library/core/src/pat.rs
@@ -6,7 +6,7 @@
 /// ```
 #[macro_export]
 #[rustc_builtin_macro(pattern_type)]
-#[unstable(feature = "core_pattern_type", issue = "none")]
+#[unstable(feature = "core_pattern_type", issue = "123646")]
 macro_rules! pattern_type {
     ($($arg:tt)*) => {
         /* compiler built-in */
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index d752151d10c..0569b8b7624 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1715,10 +1715,56 @@ impl<Ptr: fmt::Pointer> fmt::Pointer for Pin<Ptr> {
 // for other reasons, though, so we just need to take care not to allow such
 // impls to land in std.
 #[stable(feature = "pin", since = "1.33.0")]
-impl<Ptr, U> CoerceUnsized<Pin<U>> for Pin<Ptr> where Ptr: CoerceUnsized<U> {}
+impl<Ptr, U> CoerceUnsized<Pin<U>> for Pin<Ptr>
+where
+    Ptr: CoerceUnsized<U> + PinCoerceUnsized,
+    U: PinCoerceUnsized,
+{
+}
+
+#[stable(feature = "pin", since = "1.33.0")]
+impl<Ptr, U> DispatchFromDyn<Pin<U>> for Pin<Ptr>
+where
+    Ptr: DispatchFromDyn<U> + PinCoerceUnsized,
+    U: PinCoerceUnsized,
+{
+}
+
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+/// Trait that indicates that this is a pointer or a wrapper for one, where
+/// unsizing can be performed on the pointee when it is pinned.
+///
+/// # Safety
+///
+/// If this type implements `Deref`, then the concrete type returned by `deref`
+/// and `deref_mut` must not change without a modification. The following
+/// operations are not considered modifications:
+///
+/// * Moving the pointer.
+/// * Performing unsizing coercions on the pointer.
+/// * Performing dynamic dispatch with the pointer.
+/// * Calling `deref` or `deref_mut` on the pointer.
+///
+/// The concrete type of a trait object is the type that the vtable corresponds
+/// to. The concrete type of a slice is an array of the same element type and
+/// the length specified in the metadata. The concrete type of a sized type
+/// is the type itself.
+pub unsafe trait PinCoerceUnsized {}
+
+#[stable(feature = "pin", since = "1.33.0")]
+unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a T {}
+
+#[stable(feature = "pin", since = "1.33.0")]
+unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a mut T {}
+
+#[stable(feature = "pin", since = "1.33.0")]
+unsafe impl<T: PinCoerceUnsized> PinCoerceUnsized for Pin<T> {}
+
+#[stable(feature = "pin", since = "1.33.0")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for *const T {}
 
 #[stable(feature = "pin", since = "1.33.0")]
-impl<Ptr, U> DispatchFromDyn<Pin<U>> for Pin<Ptr> where Ptr: DispatchFromDyn<U> {}
+unsafe impl<T: ?Sized> PinCoerceUnsized for *mut T {}
 
 /// Constructs a <code>[Pin]<[&mut] T></code>, by pinning a `value: T` locally.
 ///
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 5989bcbcc52..09ebef89fb0 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1244,6 +1244,9 @@ mod prim_f64 {}
 /// actually implement it. For x86-64 and AArch64, ISA support is not even specified,
 /// so it will always be a software implementation significantly slower than `f64`.
 ///
+/// _Note: `f128` support is incomplete. Many platforms will not be able to link math functions. On
+/// x86 in particular, these functions do link but their results are always incorrect._
+///
 /// *[See also the `std::f128::consts` module](crate::f128::consts).*
 ///
 /// [wikipedia]: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 4a716a75039..d6be37a76bb 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -3,6 +3,7 @@ use crate::marker::Unsize;
 use crate::mem::{MaybeUninit, SizedTypeProperties};
 use crate::num::NonZero;
 use crate::ops::{CoerceUnsized, DispatchFromDyn};
+use crate::pin::PinCoerceUnsized;
 use crate::ptr::Unique;
 use crate::slice::{self, SliceIndex};
 use crate::ub_checks::assert_unsafe_precondition;
@@ -1168,9 +1169,7 @@ impl<T: ?Sized> NonNull<T> {
     /// `align`.
     ///
     /// If it is not possible to align the pointer, the implementation returns
-    /// `usize::MAX`. It is permissible for the implementation to *always*
-    /// return `usize::MAX`. Only your algorithm's performance can depend
-    /// on getting a usable offset here, not its correctness.
+    /// `usize::MAX`.
     ///
     /// The offset is expressed in number of `T` elements, and not bytes.
     ///
@@ -1178,6 +1177,15 @@ impl<T: ?Sized> NonNull<T> {
     /// beyond the allocation that the pointer points into. It is up to the caller to ensure that
     /// the returned offset is correct in all terms other than alignment.
     ///
+    /// When this is called during compile-time evaluation (which is unstable), the implementation
+    /// may return `usize::MAX` in cases where that can never happen at runtime. This is because the
+    /// actual alignment of pointers is not known yet during compile-time, so an offset with
+    /// guaranteed alignment can sometimes not be computed. For example, a buffer declared as `[u8;
+    /// N]` might be allocated at an odd or an even address, but at compile-time this is not yet
+    /// known, so the execution has to be correct for either choice. It is therefore impossible to
+    /// find an offset that is guaranteed to be 2-aligned. (This behavior is subject to change, as usual
+    /// for unstable APIs.)
+    ///
     /// # Panics
     ///
     /// The function panics if `align` is not a power-of-two.
@@ -1724,6 +1732,9 @@ impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Uns
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
 
+#[stable(feature = "pin", since = "1.33.0")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for NonNull<T> {}
+
 #[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> fmt::Debug for NonNull<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index b74d691e454..4810ebe01f9 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -1,6 +1,7 @@
 use crate::fmt;
 use crate::marker::{PhantomData, Unsize};
 use crate::ops::{CoerceUnsized, DispatchFromDyn};
+use crate::pin::PinCoerceUnsized;
 use crate::ptr::NonNull;
 
 /// A wrapper around a raw non-null `*mut T` that indicates that the possessor
@@ -166,6 +167,9 @@ impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsiz
 #[unstable(feature = "ptr_internals", issue = "none")]
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
 
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for Unique<T> {}
+
 #[unstable(feature = "ptr_internals", issue = "none")]
 impl<T: ?Sized> fmt::Debug for Unique<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 45dc828eb2e..c76157720b7 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -28,6 +28,7 @@ pub mod memchr;
     issue = "none",
     reason = "exposed from core to be reused in std;"
 )]
+#[doc(hidden)]
 pub mod sort;
 
 mod ascii;
@@ -522,7 +523,7 @@ impl<T> [T] {
     /// ```
     #[inline]
     #[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
-    #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")]
+    #[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")]
     pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> {
         if self.len() < N {
             None
@@ -2880,9 +2881,19 @@ impl<T> [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If `T: Ord` does not implement a total order the resulting order is unspecified. All
-    /// original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `T: Ord` panics.
+    /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `T` panics.
+    ///
+    /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require
+    /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the
+    /// reflexivity requirement of [`Ord`]. By using an alternative comparison function with
+    /// `slice::sort_unstable_by` such as [`f32::total_cmp`] or [`f64::total_cmp`] that defines a
+    /// [total order] users can sort slices containing floating-point values. Alternatively, if all
+    /// values in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`]
+    /// forms a [total order], it's possible to sort the slice with `sort_unstable_by(|a, b|
+    /// a.partial_cmp(b).unwrap())`.
     ///
     /// # Current implementation
     ///
@@ -2894,18 +2905,21 @@ impl<T> [T] {
     /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
     /// slice is partially sorted.
     ///
-    /// If `T: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5, 4, 1, -3, 2];
+    /// let mut v = [4, -5, 1, -3, 2];
     ///
     /// v.sort_unstable();
-    /// assert!(v == [-5, -3, 1, 2, 4]);
+    /// assert_eq!(v, [-5, -3, 1, 2, 4]);
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
     pub fn sort_unstable(&mut self)
@@ -2915,31 +2929,20 @@ impl<T> [T] {
         sort::unstable::sort(self, &mut T::lt);
     }
 
-    /// Sorts the slice with a comparator function, **without** preserving the initial order of
+    /// Sorts the slice with a comparison function, **without** preserving the initial order of
     /// equal elements.
     ///
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// The comparator function should define a total ordering for the elements in the slice. If the
-    /// ordering is not total, the order of the elements is unspecified.
-    ///
-    /// If the comparator function does not implement a total order the resulting order is
-    /// unspecified. All original elements will remain in the slice and any possible modifications
-    /// via interior mutability are observed in the input. Same is true if the comparator function
-    /// panics. A total order (for all `a`, `b` and `c`):
+    /// If the comparison function `compare` does not implement a [total order] the resulting order
+    /// of elements in the slice is unspecified. All original elements will remain in the slice and
+    /// any possible modifications via interior mutability are observed in the input. Same is true
+    /// if `compare` panics.
     ///
-    /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
-    /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
-    ///
-    /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
-    /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`.
-    ///
-    /// ```
-    /// let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0];
-    /// floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
-    /// assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]);
-    /// ```
+    /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
+    /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
+    /// examples see the [`Ord`] documentation.
     ///
     /// # Current implementation
     ///
@@ -2951,21 +2954,24 @@ impl<T> [T] {
     /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
     /// slice is partially sorted.
     ///
-    /// If `T: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if `compare` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [5, 4, 1, 3, 2];
+    /// let mut v = [4, -5, 1, -3, 2];
     /// v.sort_unstable_by(|a, b| a.cmp(b));
-    /// assert!(v == [1, 2, 3, 4, 5]);
+    /// assert_eq!(v, [-5, -3, 1, 2, 4]);
     ///
     /// // reverse sorting
     /// v.sort_unstable_by(|a, b| b.cmp(a));
-    /// assert!(v == [5, 4, 3, 2, 1]);
+    /// assert_eq!(v, [4, 2, 1, -3, -5]);
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
     pub fn sort_unstable_by<F>(&mut self, mut compare: F)
@@ -2981,9 +2987,10 @@ impl<T> [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If `K: Ord` does not implement a total order the resulting order is unspecified.
-    /// All original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `K: Ord` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `K` panics.
     ///
     /// # Current implementation
     ///
@@ -2995,18 +3002,21 @@ impl<T> [T] {
     /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
     /// slice is partially sorted.
     ///
-    /// If `K: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5i32, 4, 1, -3, 2];
+    /// let mut v = [4i32, -5, 1, -3, 2];
     ///
     /// v.sort_unstable_by_key(|k| k.abs());
-    /// assert!(v == [1, 2, -3, 4, -5]);
+    /// assert_eq!(v, [1, 2, -3, 4, -5]);
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
     pub fn sort_unstable_by_key<K, F>(&mut self, mut f: F)
@@ -3038,15 +3048,14 @@ impl<T> [T] {
     /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime
     /// for all inputs.
     ///
-    /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
-    /// slice is nearly fully sorted, where `slice::sort` may be faster.
-    ///
     /// [`sort_unstable`]: slice::sort_unstable
     ///
     /// # Panics
     ///
     /// Panics when `index >= len()`, meaning it always panics on empty slices.
     ///
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
+    ///
     /// # Examples
     ///
     /// ```
@@ -3069,6 +3078,7 @@ impl<T> [T] {
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
     pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
@@ -3099,15 +3109,14 @@ impl<T> [T] {
     /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime
     /// for all inputs.
     ///
-    /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
-    /// slice is nearly fully sorted, where `slice::sort` may be faster.
-    ///
     /// [`sort_unstable`]: slice::sort_unstable
     ///
     /// # Panics
     ///
     /// Panics when `index >= len()`, meaning it always panics on empty slices.
     ///
+    /// May panic if `compare` does not implement a [total order].
+    ///
     /// # Examples
     ///
     /// ```
@@ -3130,6 +3139,7 @@ impl<T> [T] {
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
     pub fn select_nth_unstable_by<F>(
@@ -3164,15 +3174,14 @@ impl<T> [T] {
     /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime
     /// for all inputs.
     ///
-    /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
-    /// slice is nearly fully sorted, where `slice::sort` may be faster.
-    ///
     /// [`sort_unstable`]: slice::sort_unstable
     ///
     /// # Panics
     ///
     /// Panics when `index >= len()`, meaning it always panics on empty slices.
     ///
+    /// May panic if `K: Ord` does not implement a total order.
+    ///
     /// # Examples
     ///
     /// ```
@@ -3195,6 +3204,7 @@ impl<T> [T] {
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
     pub fn select_nth_unstable_by_key<K, F>(
diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs
index 5064c5a0ae5..db0c5c72822 100644
--- a/library/core/src/slice/sort/shared/smallsort.rs
+++ b/library/core/src/slice/sort/shared/smallsort.rs
@@ -831,9 +831,9 @@ unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(
             right = right.add((!left_nonempty) as usize);
         }
 
-        // We now should have consumed the full input exactly once. This can
-        // only fail if the comparison operator fails to be Ord, in which case
-        // we will panic and never access the inconsistent state in dst.
+        // We now should have consumed the full input exactly once. This can only fail if the
+        // user-provided comparison function fails to implement a strict weak ordering. In that case
+        // we panic and never access the inconsistent state in dst.
         if left != left_end || right != right_end {
             panic_on_ord_violation();
         }
@@ -842,7 +842,21 @@ unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(
 
 #[inline(never)]
 fn panic_on_ord_violation() -> ! {
-    panic!("Ord violation");
+    // This is indicative of a logic bug in the user-provided comparison function or Ord
+    // implementation. They are expected to implement a total order as explained in the Ord
+    // documentation.
+    //
+    // By panicking we inform the user, that they have a logic bug in their program. If a strict
+    // weak ordering is not given, the concept of comparison based sorting cannot yield a sorted
+    // result. E.g.: a < b < c < a
+    //
+    // The Ord documentation requires users to implement a total order. Arguably that's
+    // unnecessarily strict in the context of sorting. Issues only arise if the weaker requirement
+    // of a strict weak ordering is violated.
+    //
+    // The panic message talks about a total order because that's what the Ord documentation talks
+    // about and requires, so as to not confuse users.
+    panic!("user-provided comparison function does not correctly implement a total order");
 }
 
 #[must_use]
diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs
index ed735e1ebfb..932e01f4401 100644
--- a/library/core/src/slice/sort/unstable/mod.rs
+++ b/library/core/src/slice/sort/unstable/mod.rs
@@ -8,7 +8,7 @@ use crate::slice::sort::shared::smallsort::insertion_sort_shift_left;
 pub(crate) mod heapsort;
 pub(crate) mod quicksort;
 
-/// Unstable sort called ipnsort by Lukas Bergdoll.
+/// Unstable sort called ipnsort by Lukas Bergdoll and Orson Peters.
 /// Design document:
 /// <https://github.com/Voultapher/sort-research-rs/blob/main/writeup/ipnsort_introduction/text.md>
 ///
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 179fbabadde..0390bb59a89 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -617,8 +617,6 @@ impl Duration {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::time::Duration;
     ///
@@ -640,8 +638,6 @@ impl Duration {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::time::Duration;
     ///
@@ -700,8 +696,6 @@ impl Duration {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::time::Duration;
     ///
@@ -758,8 +752,6 @@ impl Duration {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::time::Duration;
     ///
@@ -814,8 +806,6 @@ impl Duration {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::time::Duration;
     ///
diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs
index 6f617c8d0c2..7a6af46a743 100644
--- a/library/core/tests/pin.rs
+++ b/library/core/tests/pin.rs
@@ -29,3 +29,49 @@ fn pin_const() {
 
     pin_mut_const();
 }
+
+#[allow(unused)]
+mod pin_coerce_unsized {
+    use core::cell::{Cell, RefCell, UnsafeCell};
+    use core::pin::Pin;
+    use core::ptr::NonNull;
+
+    pub trait MyTrait {}
+    impl MyTrait for String {}
+
+    // These Pins should continue to compile.
+    // Do note that these instances of Pin types cannot be used
+    // meaningfully because all methods require a Deref/DerefMut
+    // bounds on the pointer type and Cell, RefCell and UnsafeCell
+    // do not implement Deref/DerefMut.
+
+    pub fn cell(arg: Pin<Cell<Box<String>>>) -> Pin<Cell<Box<dyn MyTrait>>> {
+        arg
+    }
+    pub fn ref_cell(arg: Pin<RefCell<Box<String>>>) -> Pin<RefCell<Box<dyn MyTrait>>> {
+        arg
+    }
+    pub fn unsafe_cell(arg: Pin<UnsafeCell<Box<String>>>) -> Pin<UnsafeCell<Box<dyn MyTrait>>> {
+        arg
+    }
+
+    // These sensible Pin coercions are possible.
+    pub fn pin_mut_ref(arg: Pin<&mut String>) -> Pin<&mut dyn MyTrait> {
+        arg
+    }
+    pub fn pin_ref(arg: Pin<&String>) -> Pin<&dyn MyTrait> {
+        arg
+    }
+    pub fn pin_ptr(arg: Pin<*const String>) -> Pin<*const dyn MyTrait> {
+        arg
+    }
+    pub fn pin_ptr_mut(arg: Pin<*mut String>) -> Pin<*mut dyn MyTrait> {
+        arg
+    }
+    pub fn pin_non_null(arg: Pin<NonNull<String>>) -> Pin<NonNull<dyn MyTrait>> {
+        arg
+    }
+    pub fn nesting_pins(arg: Pin<Pin<&String>>) -> Pin<Pin<&dyn MyTrait>> {
+        arg
+    }
+}
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index fe601855cc1..2ce284c85e2 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core", public = true }
-compiler_builtins = { version = "0.1.114" }
+compiler_builtins = { version = "0.1.118" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.14", default-features = false, features = [
diff --git a/library/std/build.rs b/library/std/build.rs
index 9b58dd53ba2..35a5977b6eb 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -11,6 +11,7 @@ fn main() {
         .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set")
         .parse()
         .unwrap();
+    let is_miri = env::var_os("CARGO_CFG_MIRI").is_some();
 
     println!("cargo:rustc-check-cfg=cfg(netbsd10)");
     if target_os == "netbsd" && env::var("RUSTC_STD_NETBSD10").is_ok() {
@@ -85,7 +86,14 @@ fn main() {
     println!("cargo:rustc-check-cfg=cfg(reliable_f16)");
     println!("cargo:rustc-check-cfg=cfg(reliable_f128)");
 
+    // This is a step beyond only having the types and basic functions available. Math functions
+    // aren't consistently available or correct.
+    println!("cargo:rustc-check-cfg=cfg(reliable_f16_math)");
+    println!("cargo:rustc-check-cfg=cfg(reliable_f128_math)");
+
     let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) {
+        // We can always enable these in Miri as that is not affected by codegen bugs.
+        _ if is_miri => true,
         // Selection failure until recent LLVM <https://github.com/llvm/llvm-project/issues/93894>
         // FIXME(llvm19): can probably be removed at the version bump
         ("loongarch64", _) => false,
@@ -113,6 +121,8 @@ fn main() {
     };
 
     let has_reliable_f128 = match (target_arch.as_str(), target_os.as_str()) {
+        // We can always enable these in Miri as that is not affected by codegen bugs.
+        _ if is_miri => true,
         // Unsupported <https://github.com/llvm/llvm-project/issues/94434>
         ("arm64ec", _) => false,
         // ABI and precision bugs <https://github.com/rust-lang/rust/issues/125109>
@@ -130,10 +140,46 @@ fn main() {
         _ => false,
     };
 
+    // These are currently empty, but will fill up as some platforms move from completely
+    // unreliable to reliable basics but unreliable math.
+
+    // LLVM is currenlty adding missing routines, <https://github.com/llvm/llvm-project/issues/93566>
+    let has_reliable_f16_math = has_reliable_f16
+        && match (target_arch.as_str(), target_os.as_str()) {
+            // FIXME: Disabled on Miri as the intrinsics are not implemented yet.
+            _ if is_miri => false,
+            // Currently nothing special. Hooray!
+            // This will change as platforms gain better better support for standard ops but math
+            // lags behind.
+            _ => true,
+        };
+
+    let has_reliable_f128_math = has_reliable_f128
+        && match (target_arch.as_str(), target_os.as_str()) {
+            // FIXME: Disabled on Miri as the intrinsics are not implemented yet.
+            _ if is_miri => false,
+            // LLVM lowers `fp128` math to `long double` symbols even on platforms where
+            // `long double` is not IEEE binary128. See
+            // <https://github.com/llvm/llvm-project/issues/44744>.
+            //
+            // This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits
+            // (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86`
+            // (ld is 80-bit extended precision).
+            ("x86_64", _) => false,
+            (_, "linux") if target_pointer_width == 64 => true,
+            _ => false,
+        };
+
     if has_reliable_f16 {
         println!("cargo:rustc-cfg=reliable_f16");
     }
     if has_reliable_f128 {
         println!("cargo:rustc-cfg=reliable_f128");
     }
+    if has_reliable_f16_math {
+        println!("cargo:rustc-cfg=reliable_f16_math");
+    }
+    if has_reliable_f128_math {
+        println!("cargo:rustc-cfg=reliable_f128_math");
+    }
 }
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index a5b00d57cef..f6df6259137 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -12,25 +12,180 @@ pub use core::f128::consts;
 
 #[cfg(not(test))]
 use crate::intrinsics;
+#[cfg(not(test))]
+use crate::sys::cmath;
 
 #[cfg(not(test))]
 impl f128 {
-    /// Raises a number to an integer power.
+    /// Returns the largest integer less than or equal to `self`.
     ///
-    /// Using this function is generally faster than using `powf`.
-    /// It might have a different sequence of rounding operations than `powf`,
-    /// so the results are not guaranteed to agree.
+    /// This function always returns the precise result.
     ///
-    /// # Unspecified precision
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 3.7_f128;
+    /// let g = 3.0_f128;
+    /// let h = -3.7_f128;
     ///
-    /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
-    /// can even differ within the same execution from one invocation to the next.
+    /// assert_eq!(f.floor(), 3.0);
+    /// assert_eq!(g.floor(), 3.0);
+    /// assert_eq!(h.floor(), -4.0);
+    /// # }
+    /// ```
     #[inline]
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    pub fn powi(self, n: i32) -> f128 {
-        unsafe { intrinsics::powif128(self, n) }
+    pub fn floor(self) -> f128 {
+        unsafe { intrinsics::floorf128(self) }
+    }
+
+    /// Returns the smallest integer greater than or equal to `self`.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 3.01_f128;
+    /// let g = 4.0_f128;
+    ///
+    /// assert_eq!(f.ceil(), 4.0);
+    /// assert_eq!(g.ceil(), 4.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "ceiling")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn ceil(self) -> f128 {
+        unsafe { intrinsics::ceilf128(self) }
+    }
+
+    /// Returns the nearest integer to `self`. If a value is half-way between two
+    /// integers, round away from `0.0`.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 3.3_f128;
+    /// let g = -3.3_f128;
+    /// let h = -3.7_f128;
+    /// let i = 3.5_f128;
+    /// let j = 4.5_f128;
+    ///
+    /// assert_eq!(f.round(), 3.0);
+    /// assert_eq!(g.round(), -3.0);
+    /// assert_eq!(h.round(), -4.0);
+    /// assert_eq!(i.round(), 4.0);
+    /// assert_eq!(j.round(), 5.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn round(self) -> f128 {
+        unsafe { intrinsics::roundf128(self) }
+    }
+
+    /// Returns the nearest integer to a number. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 3.3_f128;
+    /// let g = -3.3_f128;
+    /// let h = 3.5_f128;
+    /// let i = 4.5_f128;
+    ///
+    /// assert_eq!(f.round_ties_even(), 3.0);
+    /// assert_eq!(g.round_ties_even(), -3.0);
+    /// assert_eq!(h.round_ties_even(), 4.0);
+    /// assert_eq!(i.round_ties_even(), 4.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn round_ties_even(self) -> f128 {
+        unsafe { intrinsics::rintf128(self) }
+    }
+
+    /// Returns the integer part of `self`.
+    /// This means that non-integer numbers are always truncated towards zero.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 3.7_f128;
+    /// let g = 3.0_f128;
+    /// let h = -3.7_f128;
+    ///
+    /// assert_eq!(f.trunc(), 3.0);
+    /// assert_eq!(g.trunc(), 3.0);
+    /// assert_eq!(h.trunc(), -3.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "truncate")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn trunc(self) -> f128 {
+        unsafe { intrinsics::truncf128(self) }
+    }
+
+    /// Returns the fractional part of `self`.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 3.6_f128;
+    /// let y = -3.6_f128;
+    /// let abs_difference_x = (x.fract() - 0.6).abs();
+    /// let abs_difference_y = (y.fract() - (-0.6)).abs();
+    ///
+    /// assert!(abs_difference_x <= f128::EPSILON);
+    /// assert!(abs_difference_y <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn fract(self) -> f128 {
+        self - self.trunc()
     }
 
     /// Computes the absolute value of `self`.
@@ -41,7 +196,7 @@ impl f128 {
     ///
     /// ```
     /// #![feature(f128)]
-    /// # #[cfg(reliable_f128)] { // FIXME(f16_f128): reliable_f128
+    /// # #[cfg(reliable_f128)] {
     ///
     /// let x = 3.5_f128;
     /// let y = -3.5_f128;
@@ -61,4 +216,1129 @@ impl f128 {
         // We don't do this now because LLVM has lowering bugs for f128 math.
         Self::from_bits(self.to_bits() & !(1 << 127))
     }
+
+    /// Returns a number that represents the sign of `self`.
+    ///
+    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
+    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
+    /// - NaN if the number is NaN
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 3.5_f128;
+    ///
+    /// assert_eq!(f.signum(), 1.0);
+    /// assert_eq!(f128::NEG_INFINITY.signum(), -1.0);
+    ///
+    /// assert!(f128::NAN.signum().is_nan());
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn signum(self) -> f128 {
+        if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) }
+    }
+
+    /// Returns a number composed of the magnitude of `self` and the sign of
+    /// `sign`.
+    ///
+    /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
+    /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
+    /// `sign` is returned. Note, however, that conserving the sign bit on NaN
+    /// across arithmetical operations is not generally guaranteed.
+    /// See [explanation of NaN as a special value](primitive@f128) for more info.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 3.5_f128;
+    ///
+    /// assert_eq!(f.copysign(0.42), 3.5_f128);
+    /// assert_eq!(f.copysign(-0.42), -3.5_f128);
+    /// assert_eq!((-f).copysign(0.42), 3.5_f128);
+    /// assert_eq!((-f).copysign(-0.42), -3.5_f128);
+    ///
+    /// assert!(f128::NAN.copysign(1.0).is_nan());
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn copysign(self, sign: f128) -> f128 {
+        unsafe { intrinsics::copysignf128(self, sign) }
+    }
+
+    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` *may* be more performant than an unfused multiply-add if
+    /// the target architecture has a dedicated `fma` CPU instruction. However,
+    /// this is not always true, and will be heavily dependant on designing
+    /// algorithms with specific target hardware in mind.
+    ///
+    /// # Precision
+    ///
+    /// The result of this operation is guaranteed to be the rounded
+    /// infinite-precision result. It is specified by IEEE 754 as
+    /// `fusedMultiplyAdd` and guaranteed not to change.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let m = 10.0_f128;
+    /// let x = 4.0_f128;
+    /// let b = 60.0_f128;
+    ///
+    /// assert_eq!(m.mul_add(x, b), 100.0);
+    /// assert_eq!(m * x + b, 100.0);
+    ///
+    /// let one_plus_eps = 1.0_f128 + f128::EPSILON;
+    /// let one_minus_eps = 1.0_f128 - f128::EPSILON;
+    /// let minus_one = -1.0_f128;
+    ///
+    /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
+    /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f128::EPSILON * f128::EPSILON);
+    /// // Different rounding with the non-fused multiply and add.
+    /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn mul_add(self, a: f128, b: f128) -> f128 {
+        unsafe { intrinsics::fmaf128(self, a, b) }
+    }
+
+    /// Calculates Euclidean division, the matching method for `rem_euclid`.
+    ///
+    /// This computes the integer `n` such that
+    /// `self = n * rhs + self.rem_euclid(rhs)`.
+    /// In other words, the result is `self / rhs` rounded to the integer `n`
+    /// such that `self >= n * rhs`.
+    ///
+    /// # Precision
+    ///
+    /// The result of this operation is guaranteed to be the rounded
+    /// infinite-precision result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let a: f128 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0
+    /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0
+    /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
+    /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn div_euclid(self, rhs: f128) -> f128 {
+        let q = (self / rhs).trunc();
+        if self % rhs < 0.0 {
+            return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
+        }
+        q
+    }
+
+    /// Calculates the least nonnegative remainder of `self (mod rhs)`.
+    ///
+    /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
+    /// most cases. However, due to a floating point round-off error it can
+    /// result in `r == rhs.abs()`, violating the mathematical definition, if
+    /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
+    /// This result is not an element of the function's codomain, but it is the
+    /// closest floating point number in the real numbers and thus fulfills the
+    /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
+    /// approximately.
+    ///
+    /// # Precision
+    ///
+    /// The result of this operation is guaranteed to be the rounded
+    /// infinite-precision result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let a: f128 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(a.rem_euclid(b), 3.0);
+    /// assert_eq!((-a).rem_euclid(b), 1.0);
+    /// assert_eq!(a.rem_euclid(-b), 3.0);
+    /// assert_eq!((-a).rem_euclid(-b), 1.0);
+    /// // limitation due to round-off error
+    /// assert!((-f128::EPSILON).rem_euclid(3.0) != 0.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[doc(alias = "modulo", alias = "mod")]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn rem_euclid(self, rhs: f128) -> f128 {
+        let r = self % rhs;
+        if r < 0.0 { r + rhs.abs() } else { r }
+    }
+
+    /// Raises a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`.
+    /// It might have a different sequence of rounding operations than `powf`,
+    /// so the results are not guaranteed to agree.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powi(self, n: i32) -> f128 {
+        unsafe { intrinsics::powif128(self, n) }
+    }
+
+    /// Raises a number to a floating point power.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 2.0_f128;
+    /// let abs_difference = (x.powf(2.0) - (x * x)).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powf(self, n: f128) -> f128 {
+        unsafe { intrinsics::powf128(self, n) }
+    }
+
+    /// Returns the square root of a number.
+    ///
+    /// Returns NaN if `self` is a negative number other than `-0.0`.
+    ///
+    /// # Precision
+    ///
+    /// The result of this operation is guaranteed to be the rounded
+    /// infinite-precision result. It is specified by IEEE 754 as `squareRoot`
+    /// and guaranteed not to change.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let positive = 4.0_f128;
+    /// let negative = -4.0_f128;
+    /// let negative_zero = -0.0_f128;
+    ///
+    /// assert_eq!(positive.sqrt(), 2.0);
+    /// assert!(negative.sqrt().is_nan());
+    /// assert!(negative_zero.sqrt() == negative_zero);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn sqrt(self) -> f128 {
+        unsafe { intrinsics::sqrtf128(self) }
+    }
+
+    /// Returns `e^(self)`, (the exponential function).
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let one = 1.0f128;
+    /// // e^1
+    /// let e = one.exp();
+    ///
+    /// // ln(e) - 1 == 0
+    /// let abs_difference = (e.ln() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn exp(self) -> f128 {
+        unsafe { intrinsics::expf128(self) }
+    }
+
+    /// Returns `2^(self)`.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 2.0f128;
+    ///
+    /// // 2^2 - 4 == 0
+    /// let abs_difference = (f.exp2() - 4.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn exp2(self) -> f128 {
+        unsafe { intrinsics::exp2f128(self) }
+    }
+
+    /// Returns the natural logarithm of the number.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let one = 1.0f128;
+    /// // e^1
+    /// let e = one.exp();
+    ///
+    /// // ln(e) - 1 == 0
+    /// let abs_difference = (e.ln() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn ln(self) -> f128 {
+        unsafe { intrinsics::logf128(self) }
+    }
+
+    /// Returns the logarithm of the number with respect to an arbitrary base.
+    ///
+    /// The result might not be correctly rounded owing to implementation details;
+    /// `self.log2()` can produce more accurate results for base 2, and
+    /// `self.log10()` can produce more accurate results for base 10.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let five = 5.0f128;
+    ///
+    /// // log5(5) - 1 == 0
+    /// let abs_difference = (five.log(5.0) - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn log(self, base: f128) -> f128 {
+        self.ln() / base.ln()
+    }
+
+    /// Returns the base 2 logarithm of the number.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let two = 2.0f128;
+    ///
+    /// // log2(2) - 1 == 0
+    /// let abs_difference = (two.log2() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn log2(self) -> f128 {
+        unsafe { intrinsics::log2f128(self) }
+    }
+
+    /// Returns the base 10 logarithm of the number.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let ten = 10.0f128;
+    ///
+    /// // log10(10) - 1 == 0
+    /// let abs_difference = (ten.log10() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn log10(self) -> f128 {
+        unsafe { intrinsics::log10f128(self) }
+    }
+
+    /// Returns the cube root of a number.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    ///
+    /// This function currently corresponds to the `cbrtf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 8.0f128;
+    ///
+    /// // x^(1/3) - 2 == 0
+    /// let abs_difference = (x.cbrt() - 2.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn cbrt(self) -> f128 {
+        unsafe { cmath::cbrtf128(self) }
+    }
+
+    /// Compute the distance between the origin and a point (`x`, `y`) on the
+    /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a
+    /// right-angle triangle with other sides having length `x.abs()` and
+    /// `y.abs()`.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    ///
+    /// This function currently corresponds to the `hypotf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 2.0f128;
+    /// let y = 3.0f128;
+    ///
+    /// // sqrt(x^2 + y^2)
+    /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn hypot(self, other: f128) -> f128 {
+        unsafe { cmath::hypotf128(self, other) }
+    }
+
+    /// Computes the sine of a number (in radians).
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = std::f128::consts::FRAC_PI_2;
+    ///
+    /// let abs_difference = (x.sin() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn sin(self) -> f128 {
+        unsafe { intrinsics::sinf128(self) }
+    }
+
+    /// Computes the cosine of a number (in radians).
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 2.0 * std::f128::consts::PI;
+    ///
+    /// let abs_difference = (x.cos() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn cos(self) -> f128 {
+        unsafe { intrinsics::cosf128(self) }
+    }
+
+    /// Computes the tangent of a number (in radians).
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `tanf128` from libc on Unix and
+    /// Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = std::f128::consts::FRAC_PI_4;
+    /// let abs_difference = (x.tan() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn tan(self) -> f128 {
+        unsafe { cmath::tanf128(self) }
+    }
+
+    /// Computes the arcsine of a number. Return value is in radians in
+    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
+    /// [-1, 1].
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `asinf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = std::f128::consts::FRAC_PI_2;
+    ///
+    /// // asin(sin(pi/2))
+    /// let abs_difference = (f.sin().asin() - std::f128::consts::FRAC_PI_2).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arcsin")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn asin(self) -> f128 {
+        unsafe { cmath::asinf128(self) }
+    }
+
+    /// Computes the arccosine of a number. Return value is in radians in
+    /// the range [0, pi] or NaN if the number is outside the range
+    /// [-1, 1].
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `acosf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = std::f128::consts::FRAC_PI_4;
+    ///
+    /// // acos(cos(pi/4))
+    /// let abs_difference = (f.cos().acos() - std::f128::consts::FRAC_PI_4).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arccos")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn acos(self) -> f128 {
+        unsafe { cmath::acosf128(self) }
+    }
+
+    /// Computes the arctangent of a number. Return value is in radians in the
+    /// range [-pi/2, pi/2];
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `atanf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let f = 1.0f128;
+    ///
+    /// // atan(tan(1))
+    /// let abs_difference = (f.tan().atan() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arctan")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn atan(self) -> f128 {
+        unsafe { cmath::atanf128(self) }
+    }
+
+    /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
+    ///
+    /// * `x = 0`, `y = 0`: `0`
+    /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
+    /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
+    /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `atan2f128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// // Positive angles measured counter-clockwise
+    /// // from positive x axis
+    /// // -pi/4 radians (45 deg clockwise)
+    /// let x1 = 3.0f128;
+    /// let y1 = -3.0f128;
+    ///
+    /// // 3pi/4 radians (135 deg counter-clockwise)
+    /// let x2 = -3.0f128;
+    /// let y2 = 3.0f128;
+    ///
+    /// let abs_difference_1 = (y1.atan2(x1) - (-std::f128::consts::FRAC_PI_4)).abs();
+    /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f128::consts::FRAC_PI_4)).abs();
+    ///
+    /// assert!(abs_difference_1 <= f128::EPSILON);
+    /// assert!(abs_difference_2 <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn atan2(self, other: f128) -> f128 {
+        unsafe { cmath::atan2f128(self, other) }
+    }
+
+    /// Simultaneously computes the sine and cosine of the number, `x`. Returns
+    /// `(sin(x), cos(x))`.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `(f128::sin(x),
+    /// f128::cos(x))`. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = std::f128::consts::FRAC_PI_4;
+    /// let f = x.sin_cos();
+    ///
+    /// let abs_difference_0 = (f.0 - x.sin()).abs();
+    /// let abs_difference_1 = (f.1 - x.cos()).abs();
+    ///
+    /// assert!(abs_difference_0 <= f128::EPSILON);
+    /// assert!(abs_difference_1 <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "sincos")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    pub fn sin_cos(self) -> (f128, f128) {
+        (self.sin(), self.cos())
+    }
+
+    /// Returns `e^(self) - 1` in a way that is accurate even if the
+    /// number is close to zero.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `expm1f128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 1e-8_f128;
+    ///
+    /// // for very small x, e^x is approximately 1 + x + x^2 / 2
+    /// let approx = x + x * x / 2.0;
+    /// let abs_difference = (x.exp_m1() - approx).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn exp_m1(self) -> f128 {
+        unsafe { cmath::expm1f128(self) }
+    }
+
+    /// Returns `ln(1+n)` (natural logarithm) more accurately than if
+    /// the operations were performed separately.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `log1pf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 1e-8_f128;
+    ///
+    /// // for very small x, ln(1 + x) is approximately x - x^2 / 2
+    /// let approx = x - x * x / 2.0;
+    /// let abs_difference = (x.ln_1p() - approx).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "log1p")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    pub fn ln_1p(self) -> f128 {
+        unsafe { cmath::log1pf128(self) }
+    }
+
+    /// Hyperbolic sine function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `sinhf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let e = std::f128::consts::E;
+    /// let x = 1.0f128;
+    ///
+    /// let f = x.sinh();
+    /// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
+    /// let g = ((e * e) - 1.0) / (2.0 * e);
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn sinh(self) -> f128 {
+        unsafe { cmath::sinhf128(self) }
+    }
+
+    /// Hyperbolic cosine function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `coshf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let e = std::f128::consts::E;
+    /// let x = 1.0f128;
+    /// let f = x.cosh();
+    /// // Solving cosh() at 1 gives this result
+    /// let g = ((e * e) + 1.0) / (2.0 * e);
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// // Same result
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn cosh(self) -> f128 {
+        unsafe { cmath::coshf128(self) }
+    }
+
+    /// Hyperbolic tangent function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `tanhf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let e = std::f128::consts::E;
+    /// let x = 1.0f128;
+    ///
+    /// let f = x.tanh();
+    /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
+    /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2));
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn tanh(self) -> f128 {
+        unsafe { cmath::tanhf128(self) }
+    }
+
+    /// Inverse hyperbolic sine function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 1.0f128;
+    /// let f = x.sinh().asinh();
+    ///
+    /// let abs_difference = (f - x).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arcsinh")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn asinh(self) -> f128 {
+        let ax = self.abs();
+        let ix = 1.0 / ax;
+        (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
+    }
+
+    /// Inverse hyperbolic cosine function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 1.0f128;
+    /// let f = x.cosh().acosh();
+    ///
+    /// let abs_difference = (f - x).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arccosh")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn acosh(self) -> f128 {
+        if self < 1.0 {
+            Self::NAN
+        } else {
+            (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
+        }
+    }
+
+    /// Inverse hyperbolic tangent function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let e = std::f128::consts::E;
+    /// let f = e.tanh().atanh();
+    ///
+    /// let abs_difference = (f - e).abs();
+    ///
+    /// assert!(abs_difference <= 1e-5);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arctanh")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn atanh(self) -> f128 {
+        0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
+    }
+
+    /// Gamma function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `tgammaf128` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// #![feature(float_gamma)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 5.0f128;
+    ///
+    /// let abs_difference = (x.gamma() - 24.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn gamma(self) -> f128 {
+        unsafe { cmath::tgammaf128(self) }
+    }
+
+    /// Natural logarithm of the absolute value of the gamma function
+    ///
+    /// The integer part of the tuple indicates the sign of the gamma function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `lgammaf128_r` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// #![feature(float_gamma)]
+    /// # #[cfg(reliable_f128_math)] {
+    ///
+    /// let x = 2.0f128;
+    ///
+    /// let abs_difference = (x.ln_gamma().0 - 0.0).abs();
+    ///
+    /// assert!(abs_difference <= f128::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn ln_gamma(self) -> (f128, i32) {
+        let mut signgamp: i32 = 0;
+        let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) };
+        (x, signgamp)
+    }
 }
diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs
index 162c8dbad81..7051c051bf7 100644
--- a/library/std/src/f128/tests.rs
+++ b/library/std/src/f128/tests.rs
@@ -4,6 +4,21 @@
 use crate::f128::consts;
 use crate::num::{FpCategory as Fp, *};
 
+// Note these tolerances make sense around zero, but not for more extreme exponents.
+
+/// For operations that are near exact, usually not involving math of different
+/// signs.
+const TOL_PRECISE: f128 = 1e-28;
+
+/// Default tolerances. Works for values that should be near precise but not exact. Roughly
+/// the precision carried by `100 * 100`.
+const TOL: f128 = 1e-12;
+
+/// Tolerances for math that is allowed to be imprecise, usually due to multiple chained
+/// operations.
+#[cfg(reliable_f128_math)]
+const TOL_IMPR: f128 = 1e-10;
+
 /// Smallest number
 const TINY_BITS: u128 = 0x1;
 
@@ -41,7 +56,33 @@ fn test_num_f128() {
     test_num(10f128, 2f128);
 }
 
-// FIXME(f16_f128): add min and max tests when available
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_min_nan() {
+    assert_eq!(f128::NAN.min(2.0), 2.0);
+    assert_eq!(2.0f128.min(f128::NAN), 2.0);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_max_nan() {
+    assert_eq!(f128::NAN.max(2.0), 2.0);
+    assert_eq!(2.0f128.max(f128::NAN), 2.0);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_minimum() {
+    assert!(f128::NAN.minimum(2.0).is_nan());
+    assert!(2.0f128.minimum(f128::NAN).is_nan());
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_maximum() {
+    assert!(f128::NAN.maximum(2.0).is_nan());
+    assert!(2.0f128.maximum(f128::NAN).is_nan());
+}
 
 #[test]
 fn test_nan() {
@@ -191,9 +232,100 @@ fn test_classify() {
     assert_eq!(1e-4932f128.classify(), Fp::Subnormal);
 }
 
-// FIXME(f16_f128): add missing math functions when available
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_floor() {
+    assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.3f128.floor(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.5f128.floor(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.7f128.floor(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(0.0f128.floor(), 0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-0.0f128).floor(), -0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.0f128).floor(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.3f128).floor(), -2.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.5f128).floor(), -2.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.7f128).floor(), -2.0f128, TOL_PRECISE);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_ceil() {
+    assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.3f128.ceil(), 2.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.5f128.ceil(), 2.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.7f128.ceil(), 2.0f128, TOL_PRECISE);
+    assert_approx_eq!(0.0f128.ceil(), 0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-0.0f128).ceil(), -0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.0f128).ceil(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.3f128).ceil(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.5f128).ceil(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.7f128).ceil(), -1.0f128, TOL_PRECISE);
+}
 
 #[test]
+#[cfg(reliable_f128_math)]
+fn test_round() {
+    assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.0f128.round(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.3f128.round(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.5f128.round(), 2.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.7f128.round(), 2.0f128, TOL_PRECISE);
+    assert_approx_eq!(0.0f128.round(), 0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-0.0f128).round(), -0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.0f128).round(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.3f128).round(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.5f128).round(), -2.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.7f128).round(), -2.0f128, TOL_PRECISE);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_round_ties_even() {
+    assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.0f128.round_ties_even(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.3f128.round_ties_even(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.5f128.round_ties_even(), 2.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.7f128.round_ties_even(), 2.0f128, TOL_PRECISE);
+    assert_approx_eq!(0.0f128.round_ties_even(), 0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-0.0f128).round_ties_even(), -0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.0f128).round_ties_even(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.3f128).round_ties_even(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.5f128).round_ties_even(), -2.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.7f128).round_ties_even(), -2.0f128, TOL_PRECISE);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_trunc() {
+    assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.3f128.trunc(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.5f128.trunc(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.7f128.trunc(), 1.0f128, TOL_PRECISE);
+    assert_approx_eq!(0.0f128.trunc(), 0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-0.0f128).trunc(), -0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.0f128).trunc(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.3f128).trunc(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.5f128).trunc(), -1.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.7f128).trunc(), -1.0f128, TOL_PRECISE);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_fract() {
+    assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE);
+    assert_approx_eq!(1.3f128.fract(), 0.3f128, TOL_PRECISE);
+    assert_approx_eq!(1.5f128.fract(), 0.5f128, TOL_PRECISE);
+    assert_approx_eq!(1.7f128.fract(), 0.7f128, TOL_PRECISE);
+    assert_approx_eq!(0.0f128.fract(), 0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-0.0f128).fract(), -0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.0f128).fract(), -0.0f128, TOL_PRECISE);
+    assert_approx_eq!((-1.3f128).fract(), -0.3f128, TOL_PRECISE);
+    assert_approx_eq!((-1.5f128).fract(), -0.5f128, TOL_PRECISE);
+    assert_approx_eq!((-1.7f128).fract(), -0.7f128, TOL_PRECISE);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
 fn test_abs() {
     assert_eq!(f128::INFINITY.abs(), f128::INFINITY);
     assert_eq!(1f128.abs(), 1f128);
@@ -293,6 +425,24 @@ fn test_next_down() {
 }
 
 #[test]
+#[cfg(reliable_f128_math)]
+fn test_mul_add() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    assert_approx_eq!(12.3f128.mul_add(4.5, 6.7), 62.05, TOL_PRECISE);
+    assert_approx_eq!((-12.3f128).mul_add(-4.5, -6.7), 48.65, TOL_PRECISE);
+    assert_approx_eq!(0.0f128.mul_add(8.9, 1.2), 1.2, TOL_PRECISE);
+    assert_approx_eq!(3.4f128.mul_add(-0.0, 5.6), 5.6, TOL_PRECISE);
+    assert!(nan.mul_add(7.8, 9.0).is_nan());
+    assert_eq!(inf.mul_add(7.8, 9.0), inf);
+    assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
+    assert_eq!(8.9f128.mul_add(inf, 3.2), inf);
+    assert_eq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
 fn test_recip() {
     let nan: f128 = f128::NAN;
     let inf: f128 = f128::INFINITY;
@@ -301,11 +451,161 @@ fn test_recip() {
     assert_eq!(2.0f128.recip(), 0.5);
     assert_eq!((-0.4f128).recip(), -2.5);
     assert_eq!(0.0f128.recip(), inf);
+    assert_approx_eq!(
+        f128::MAX.recip(),
+        8.40525785778023376565669454330438228902076605e-4933,
+        1e-4900
+    );
     assert!(nan.recip().is_nan());
     assert_eq!(inf.recip(), 0.0);
     assert_eq!(neg_inf.recip(), 0.0);
 }
 
+// Many math functions allow for less accurate results, so the next tolerance up is used
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_powi() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    assert_eq!(1.0f128.powi(1), 1.0);
+    assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL);
+    assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL);
+    assert_eq!(8.3f128.powi(0), 1.0);
+    assert!(nan.powi(2).is_nan());
+    assert_eq!(inf.powi(3), inf);
+    assert_eq!(neg_inf.powi(2), inf);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_powf() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    assert_eq!(1.0f128.powf(1.0), 1.0);
+    assert_approx_eq!(3.4f128.powf(4.5), 246.40818323761892815995637964326426756, TOL_IMPR);
+    assert_approx_eq!(2.7f128.powf(-3.2), 0.041652009108526178281070304373500889273, TOL_IMPR);
+    assert_approx_eq!((-3.1f128).powf(2.0), 9.6100000000000005506706202140776519387, TOL_IMPR);
+    assert_approx_eq!(5.9f128.powf(-2.0), 0.028727377190462507313100483690639638451, TOL_IMPR);
+    assert_eq!(8.3f128.powf(0.0), 1.0);
+    assert!(nan.powf(2.0).is_nan());
+    assert_eq!(inf.powf(2.0), inf);
+    assert_eq!(neg_inf.powf(3.0), neg_inf);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_sqrt_domain() {
+    assert!(f128::NAN.sqrt().is_nan());
+    assert!(f128::NEG_INFINITY.sqrt().is_nan());
+    assert!((-1.0f128).sqrt().is_nan());
+    assert_eq!((-0.0f128).sqrt(), -0.0);
+    assert_eq!(0.0f128.sqrt(), 0.0);
+    assert_eq!(1.0f128.sqrt(), 1.0);
+    assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_exp() {
+    assert_eq!(1.0, 0.0f128.exp());
+    assert_approx_eq!(consts::E, 1.0f128.exp(), TOL);
+    assert_approx_eq!(148.41315910257660342111558004055227962348775, 5.0f128.exp(), TOL);
+
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    let nan: f128 = f128::NAN;
+    assert_eq!(inf, inf.exp());
+    assert_eq!(0.0, neg_inf.exp());
+    assert!(nan.exp().is_nan());
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_exp2() {
+    assert_eq!(32.0, 5.0f128.exp2());
+    assert_eq!(1.0, 0.0f128.exp2());
+
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    let nan: f128 = f128::NAN;
+    assert_eq!(inf, inf.exp2());
+    assert_eq!(0.0, neg_inf.exp2());
+    assert!(nan.exp2().is_nan());
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_ln() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    assert_approx_eq!(1.0f128.exp().ln(), 1.0, TOL);
+    assert!(nan.ln().is_nan());
+    assert_eq!(inf.ln(), inf);
+    assert!(neg_inf.ln().is_nan());
+    assert!((-2.3f128).ln().is_nan());
+    assert_eq!((-0.0f128).ln(), neg_inf);
+    assert_eq!(0.0f128.ln(), neg_inf);
+    assert_approx_eq!(4.0f128.ln(), 1.3862943611198906188344642429163531366, TOL);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_log() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    assert_eq!(10.0f128.log(10.0), 1.0);
+    assert_approx_eq!(2.3f128.log(3.5), 0.66485771361478710036766645911922010272, TOL);
+    assert_eq!(1.0f128.exp().log(1.0f128.exp()), 1.0);
+    assert!(1.0f128.log(1.0).is_nan());
+    assert!(1.0f128.log(-13.9).is_nan());
+    assert!(nan.log(2.3).is_nan());
+    assert_eq!(inf.log(10.0), inf);
+    assert!(neg_inf.log(8.8).is_nan());
+    assert!((-2.3f128).log(0.1).is_nan());
+    assert_eq!((-0.0f128).log(2.0), neg_inf);
+    assert_eq!(0.0f128.log(7.0), neg_inf);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_log2() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    assert_approx_eq!(10.0f128.log2(), 3.32192809488736234787031942948939017, TOL);
+    assert_approx_eq!(2.3f128.log2(), 1.2016338611696504130002982471978765921, TOL);
+    assert_approx_eq!(1.0f128.exp().log2(), 1.4426950408889634073599246810018921381, TOL);
+    assert!(nan.log2().is_nan());
+    assert_eq!(inf.log2(), inf);
+    assert!(neg_inf.log2().is_nan());
+    assert!((-2.3f128).log2().is_nan());
+    assert_eq!((-0.0f128).log2(), neg_inf);
+    assert_eq!(0.0f128.log2(), neg_inf);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_log10() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    assert_eq!(10.0f128.log10(), 1.0);
+    assert_approx_eq!(2.3f128.log10(), 0.36172783601759284532595218865859309898, TOL);
+    assert_approx_eq!(1.0f128.exp().log10(), 0.43429448190325182765112891891660508222, TOL);
+    assert_eq!(1.0f128.log10(), 0.0);
+    assert!(nan.log10().is_nan());
+    assert_eq!(inf.log10(), inf);
+    assert!(neg_inf.log10().is_nan());
+    assert!((-2.3f128).log10().is_nan());
+    assert_eq!((-0.0f128).log10(), neg_inf);
+    assert_eq!(0.0f128.log10(), neg_inf);
+}
+
 #[test]
 fn test_to_degrees() {
     let pi: f128 = consts::PI;
@@ -313,8 +613,8 @@ fn test_to_degrees() {
     let inf: f128 = f128::INFINITY;
     let neg_inf: f128 = f128::NEG_INFINITY;
     assert_eq!(0.0f128.to_degrees(), 0.0);
-    assert_approx_eq!((-5.8f128).to_degrees(), -332.315521);
-    assert_eq!(pi.to_degrees(), 180.0);
+    assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL);
+    assert_approx_eq!(pi.to_degrees(), 180.0, TOL);
     assert!(nan.to_degrees().is_nan());
     assert_eq!(inf.to_degrees(), inf);
     assert_eq!(neg_inf.to_degrees(), neg_inf);
@@ -328,19 +628,122 @@ fn test_to_radians() {
     let inf: f128 = f128::INFINITY;
     let neg_inf: f128 = f128::NEG_INFINITY;
     assert_eq!(0.0f128.to_radians(), 0.0);
-    assert_approx_eq!(154.6f128.to_radians(), 2.698279);
-    assert_approx_eq!((-332.31f128).to_radians(), -5.799903);
+    assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL);
+    assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL);
     // check approx rather than exact because round trip for pi doesn't fall on an exactly
     // representable value (unlike `f32` and `f64`).
-    assert_approx_eq!(180.0f128.to_radians(), pi);
+    assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE);
     assert!(nan.to_radians().is_nan());
     assert_eq!(inf.to_radians(), inf);
     assert_eq!(neg_inf.to_radians(), neg_inf);
 }
 
 #[test]
+#[cfg(reliable_f128_math)]
+fn test_asinh() {
+    // Lower accuracy results are allowed, use increased tolerances
+    assert_eq!(0.0f128.asinh(), 0.0f128);
+    assert_eq!((-0.0f128).asinh(), -0.0f128);
+
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    let nan: f128 = f128::NAN;
+    assert_eq!(inf.asinh(), inf);
+    assert_eq!(neg_inf.asinh(), neg_inf);
+    assert!(nan.asinh().is_nan());
+    assert!((-0.0f128).asinh().is_sign_negative());
+
+    // issue 63271
+    assert_approx_eq!(2.0f128.asinh(), 1.443635475178810342493276740273105f128, TOL_IMPR);
+    assert_approx_eq!((-2.0f128).asinh(), -1.443635475178810342493276740273105f128, TOL_IMPR);
+    // regression test for the catastrophic cancellation fixed in 72486
+    assert_approx_eq!(
+        (-67452098.07139316f128).asinh(),
+        -18.720075426274544393985484294000831757220,
+        TOL_IMPR
+    );
+
+    // test for low accuracy from issue 104548
+    assert_approx_eq!(60.0f128, 60.0f128.sinh().asinh(), TOL_IMPR);
+    // mul needed for approximate comparison to be meaningful
+    assert_approx_eq!(1.0f128, 1e-15f128.sinh().asinh() * 1e15f128, TOL_IMPR);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_acosh() {
+    assert_eq!(1.0f128.acosh(), 0.0f128);
+    assert!(0.999f128.acosh().is_nan());
+
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    let nan: f128 = f128::NAN;
+    assert_eq!(inf.acosh(), inf);
+    assert!(neg_inf.acosh().is_nan());
+    assert!(nan.acosh().is_nan());
+    assert_approx_eq!(2.0f128.acosh(), 1.31695789692481670862504634730796844f128, TOL_IMPR);
+    assert_approx_eq!(3.0f128.acosh(), 1.76274717403908605046521864995958461f128, TOL_IMPR);
+
+    // test for low accuracy from issue 104548
+    assert_approx_eq!(60.0f128, 60.0f128.cosh().acosh(), TOL_IMPR);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_atanh() {
+    assert_eq!(0.0f128.atanh(), 0.0f128);
+    assert_eq!((-0.0f128).atanh(), -0.0f128);
+
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    let nan: f128 = f128::NAN;
+    assert_eq!(1.0f128.atanh(), inf);
+    assert_eq!((-1.0f128).atanh(), neg_inf);
+    assert!(2f128.atanh().atanh().is_nan());
+    assert!((-2f128).atanh().atanh().is_nan());
+    assert!(inf.atanh().is_nan());
+    assert!(neg_inf.atanh().is_nan());
+    assert!(nan.atanh().is_nan());
+    assert_approx_eq!(0.5f128.atanh(), 0.54930614433405484569762261846126285f128, TOL_IMPR);
+    assert_approx_eq!((-0.5f128).atanh(), -0.54930614433405484569762261846126285f128, TOL_IMPR);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_gamma() {
+    // precision can differ among platforms
+    assert_approx_eq!(1.0f128.gamma(), 1.0f128, TOL_IMPR);
+    assert_approx_eq!(2.0f128.gamma(), 1.0f128, TOL_IMPR);
+    assert_approx_eq!(3.0f128.gamma(), 2.0f128, TOL_IMPR);
+    assert_approx_eq!(4.0f128.gamma(), 6.0f128, TOL_IMPR);
+    assert_approx_eq!(5.0f128.gamma(), 24.0f128, TOL_IMPR);
+    assert_approx_eq!(0.5f128.gamma(), consts::PI.sqrt(), TOL_IMPR);
+    assert_approx_eq!((-0.5f128).gamma(), -2.0 * consts::PI.sqrt(), TOL_IMPR);
+    assert_eq!(0.0f128.gamma(), f128::INFINITY);
+    assert_eq!((-0.0f128).gamma(), f128::NEG_INFINITY);
+    assert!((-1.0f128).gamma().is_nan());
+    assert!((-2.0f128).gamma().is_nan());
+    assert!(f128::NAN.gamma().is_nan());
+    assert!(f128::NEG_INFINITY.gamma().is_nan());
+    assert_eq!(f128::INFINITY.gamma(), f128::INFINITY);
+    assert_eq!(1760.9f128.gamma(), f128::INFINITY);
+}
+
+#[test]
+#[cfg(reliable_f128_math)]
+fn test_ln_gamma() {
+    assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR);
+    assert_eq!(1.0f128.ln_gamma().1, 1);
+    assert_approx_eq!(2.0f128.ln_gamma().0, 0.0f128, TOL_IMPR);
+    assert_eq!(2.0f128.ln_gamma().1, 1);
+    assert_approx_eq!(3.0f128.ln_gamma().0, 2.0f128.ln(), TOL_IMPR);
+    assert_eq!(3.0f128.ln_gamma().1, 1);
+    assert_approx_eq!((-0.5f128).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_IMPR);
+    assert_eq!((-0.5f128).ln_gamma().1, -1);
+}
+
+#[test]
 fn test_real_consts() {
-    // FIXME(f16_f128): add math tests when available
     use super::consts;
 
     let pi: f128 = consts::PI;
@@ -351,29 +754,34 @@ fn test_real_consts() {
     let frac_pi_8: f128 = consts::FRAC_PI_8;
     let frac_1_pi: f128 = consts::FRAC_1_PI;
     let frac_2_pi: f128 = consts::FRAC_2_PI;
-    // let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI;
-    // let sqrt2: f128 = consts::SQRT_2;
-    // let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2;
-    // let e: f128 = consts::E;
-    // let log2_e: f128 = consts::LOG2_E;
-    // let log10_e: f128 = consts::LOG10_E;
-    // let ln_2: f128 = consts::LN_2;
-    // let ln_10: f128 = consts::LN_10;
-
-    assert_approx_eq!(frac_pi_2, pi / 2f128);
-    assert_approx_eq!(frac_pi_3, pi / 3f128);
-    assert_approx_eq!(frac_pi_4, pi / 4f128);
-    assert_approx_eq!(frac_pi_6, pi / 6f128);
-    assert_approx_eq!(frac_pi_8, pi / 8f128);
-    assert_approx_eq!(frac_1_pi, 1f128 / pi);
-    assert_approx_eq!(frac_2_pi, 2f128 / pi);
-    // assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt());
-    // assert_approx_eq!(sqrt2, 2f128.sqrt());
-    // assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt());
-    // assert_approx_eq!(log2_e, e.log2());
-    // assert_approx_eq!(log10_e, e.log10());
-    // assert_approx_eq!(ln_2, 2f128.ln());
-    // assert_approx_eq!(ln_10, 10f128.ln());
+
+    assert_approx_eq!(frac_pi_2, pi / 2f128, TOL_PRECISE);
+    assert_approx_eq!(frac_pi_3, pi / 3f128, TOL_PRECISE);
+    assert_approx_eq!(frac_pi_4, pi / 4f128, TOL_PRECISE);
+    assert_approx_eq!(frac_pi_6, pi / 6f128, TOL_PRECISE);
+    assert_approx_eq!(frac_pi_8, pi / 8f128, TOL_PRECISE);
+    assert_approx_eq!(frac_1_pi, 1f128 / pi, TOL_PRECISE);
+    assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE);
+
+    #[cfg(reliable_f128_math)]
+    {
+        let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI;
+        let sqrt2: f128 = consts::SQRT_2;
+        let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2;
+        let e: f128 = consts::E;
+        let log2_e: f128 = consts::LOG2_E;
+        let log10_e: f128 = consts::LOG10_E;
+        let ln_2: f128 = consts::LN_2;
+        let ln_10: f128 = consts::LN_10;
+
+        assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt(), TOL_PRECISE);
+        assert_approx_eq!(sqrt2, 2f128.sqrt(), TOL_PRECISE);
+        assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt(), TOL_PRECISE);
+        assert_approx_eq!(log2_e, e.log2(), TOL_PRECISE);
+        assert_approx_eq!(log10_e, e.log10(), TOL_PRECISE);
+        assert_approx_eq!(ln_2, 2f128.ln(), TOL_PRECISE);
+        assert_approx_eq!(ln_10, 10f128.ln(), TOL_PRECISE);
+    }
 }
 
 #[test]
@@ -382,10 +790,10 @@ fn test_float_bits_conv() {
     assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000);
     assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000);
     assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000);
-    assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0);
-    assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5);
-    assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0);
-    assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25);
+    assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0, TOL_PRECISE);
+    assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5, TOL_PRECISE);
+    assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0, TOL_PRECISE);
+    assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25, TOL_PRECISE);
 
     // Check that NaNs roundtrip their bits regardless of signaling-ness
     // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index e3024defed7..10908332762 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -12,25 +12,180 @@ pub use core::f16::consts;
 
 #[cfg(not(test))]
 use crate::intrinsics;
+#[cfg(not(test))]
+use crate::sys::cmath;
 
 #[cfg(not(test))]
 impl f16 {
-    /// Raises a number to an integer power.
+    /// Returns the largest integer less than or equal to `self`.
     ///
-    /// Using this function is generally faster than using `powf`.
-    /// It might have a different sequence of rounding operations than `powf`,
-    /// so the results are not guaranteed to agree.
+    /// This function always returns the precise result.
     ///
-    /// # Unspecified precision
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 3.7_f16;
+    /// let g = 3.0_f16;
+    /// let h = -3.7_f16;
     ///
-    /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
-    /// can even differ within the same execution from one invocation to the next.
+    /// assert_eq!(f.floor(), 3.0);
+    /// assert_eq!(g.floor(), 3.0);
+    /// assert_eq!(h.floor(), -4.0);
+    /// # }
+    /// ```
     #[inline]
     #[rustc_allow_incoherent_impl]
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    pub fn powi(self, n: i32) -> f16 {
-        unsafe { intrinsics::powif16(self, n) }
+    pub fn floor(self) -> f16 {
+        unsafe { intrinsics::floorf16(self) }
+    }
+
+    /// Returns the smallest integer greater than or equal to `self`.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 3.01_f16;
+    /// let g = 4.0_f16;
+    ///
+    /// assert_eq!(f.ceil(), 4.0);
+    /// assert_eq!(g.ceil(), 4.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "ceiling")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn ceil(self) -> f16 {
+        unsafe { intrinsics::ceilf16(self) }
+    }
+
+    /// Returns the nearest integer to `self`. If a value is half-way between two
+    /// integers, round away from `0.0`.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 3.3_f16;
+    /// let g = -3.3_f16;
+    /// let h = -3.7_f16;
+    /// let i = 3.5_f16;
+    /// let j = 4.5_f16;
+    ///
+    /// assert_eq!(f.round(), 3.0);
+    /// assert_eq!(g.round(), -3.0);
+    /// assert_eq!(h.round(), -4.0);
+    /// assert_eq!(i.round(), 4.0);
+    /// assert_eq!(j.round(), 5.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn round(self) -> f16 {
+        unsafe { intrinsics::roundf16(self) }
+    }
+
+    /// Returns the nearest integer to a number. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 3.3_f16;
+    /// let g = -3.3_f16;
+    /// let h = 3.5_f16;
+    /// let i = 4.5_f16;
+    ///
+    /// assert_eq!(f.round_ties_even(), 3.0);
+    /// assert_eq!(g.round_ties_even(), -3.0);
+    /// assert_eq!(h.round_ties_even(), 4.0);
+    /// assert_eq!(i.round_ties_even(), 4.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn round_ties_even(self) -> f16 {
+        unsafe { intrinsics::rintf16(self) }
+    }
+
+    /// Returns the integer part of `self`.
+    /// This means that non-integer numbers are always truncated towards zero.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 3.7_f16;
+    /// let g = 3.0_f16;
+    /// let h = -3.7_f16;
+    ///
+    /// assert_eq!(f.trunc(), 3.0);
+    /// assert_eq!(g.trunc(), 3.0);
+    /// assert_eq!(h.trunc(), -3.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "truncate")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn trunc(self) -> f16 {
+        unsafe { intrinsics::truncf16(self) }
+    }
+
+    /// Returns the fractional part of `self`.
+    ///
+    /// This function always returns the precise result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 3.6_f16;
+    /// let y = -3.6_f16;
+    /// let abs_difference_x = (x.fract() - 0.6).abs();
+    /// let abs_difference_y = (y.fract() - (-0.6)).abs();
+    ///
+    /// assert!(abs_difference_x <= f16::EPSILON);
+    /// assert!(abs_difference_y <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn fract(self) -> f16 {
+        self - self.trunc()
     }
 
     /// Computes the absolute value of `self`.
@@ -60,4 +215,1127 @@ impl f16 {
         // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available
         Self::from_bits(self.to_bits() & !(1 << 15))
     }
+
+    /// Returns a number that represents the sign of `self`.
+    ///
+    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
+    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
+    /// - NaN if the number is NaN
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 3.5_f16;
+    ///
+    /// assert_eq!(f.signum(), 1.0);
+    /// assert_eq!(f16::NEG_INFINITY.signum(), -1.0);
+    ///
+    /// assert!(f16::NAN.signum().is_nan());
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn signum(self) -> f16 {
+        if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) }
+    }
+
+    /// Returns a number composed of the magnitude of `self` and the sign of
+    /// `sign`.
+    ///
+    /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
+    /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
+    /// `sign` is returned. Note, however, that conserving the sign bit on NaN
+    /// across arithmetical operations is not generally guaranteed.
+    /// See [explanation of NaN as a special value](primitive@f16) for more info.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 3.5_f16;
+    ///
+    /// assert_eq!(f.copysign(0.42), 3.5_f16);
+    /// assert_eq!(f.copysign(-0.42), -3.5_f16);
+    /// assert_eq!((-f).copysign(0.42), 3.5_f16);
+    /// assert_eq!((-f).copysign(-0.42), -3.5_f16);
+    ///
+    /// assert!(f16::NAN.copysign(1.0).is_nan());
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn copysign(self, sign: f16) -> f16 {
+        unsafe { intrinsics::copysignf16(self, sign) }
+    }
+
+    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+    /// error, yielding a more accurate result than an unfused multiply-add.
+    ///
+    /// Using `mul_add` *may* be more performant than an unfused multiply-add if
+    /// the target architecture has a dedicated `fma` CPU instruction. However,
+    /// this is not always true, and will be heavily dependant on designing
+    /// algorithms with specific target hardware in mind.
+    ///
+    /// # Precision
+    ///
+    /// The result of this operation is guaranteed to be the rounded
+    /// infinite-precision result. It is specified by IEEE 754 as
+    /// `fusedMultiplyAdd` and guaranteed not to change.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let m = 10.0_f16;
+    /// let x = 4.0_f16;
+    /// let b = 60.0_f16;
+    ///
+    /// assert_eq!(m.mul_add(x, b), 100.0);
+    /// assert_eq!(m * x + b, 100.0);
+    ///
+    /// let one_plus_eps = 1.0_f16 + f16::EPSILON;
+    /// let one_minus_eps = 1.0_f16 - f16::EPSILON;
+    /// let minus_one = -1.0_f16;
+    ///
+    /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
+    /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f16::EPSILON * f16::EPSILON);
+    /// // Different rounding with the non-fused multiply and add.
+    /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn mul_add(self, a: f16, b: f16) -> f16 {
+        unsafe { intrinsics::fmaf16(self, a, b) }
+    }
+
+    /// Calculates Euclidean division, the matching method for `rem_euclid`.
+    ///
+    /// This computes the integer `n` such that
+    /// `self = n * rhs + self.rem_euclid(rhs)`.
+    /// In other words, the result is `self / rhs` rounded to the integer `n`
+    /// such that `self >= n * rhs`.
+    ///
+    /// # Precision
+    ///
+    /// The result of this operation is guaranteed to be the rounded
+    /// infinite-precision result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let a: f16 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0
+    /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0
+    /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
+    /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn div_euclid(self, rhs: f16) -> f16 {
+        let q = (self / rhs).trunc();
+        if self % rhs < 0.0 {
+            return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
+        }
+        q
+    }
+
+    /// Calculates the least nonnegative remainder of `self (mod rhs)`.
+    ///
+    /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
+    /// most cases. However, due to a floating point round-off error it can
+    /// result in `r == rhs.abs()`, violating the mathematical definition, if
+    /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
+    /// This result is not an element of the function's codomain, but it is the
+    /// closest floating point number in the real numbers and thus fulfills the
+    /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
+    /// approximately.
+    ///
+    /// # Precision
+    ///
+    /// The result of this operation is guaranteed to be the rounded
+    /// infinite-precision result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let a: f16 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(a.rem_euclid(b), 3.0);
+    /// assert_eq!((-a).rem_euclid(b), 1.0);
+    /// assert_eq!(a.rem_euclid(-b), 3.0);
+    /// assert_eq!((-a).rem_euclid(-b), 1.0);
+    /// // limitation due to round-off error
+    /// assert!((-f16::EPSILON).rem_euclid(3.0) != 0.0);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[doc(alias = "modulo", alias = "mod")]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn rem_euclid(self, rhs: f16) -> f16 {
+        let r = self % rhs;
+        if r < 0.0 { r + rhs.abs() } else { r }
+    }
+
+    /// Raises a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`.
+    /// It might have a different sequence of rounding operations than `powf`,
+    /// so the results are not guaranteed to agree.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powi(self, n: i32) -> f16 {
+        unsafe { intrinsics::powif16(self, n) }
+    }
+
+    /// Raises a number to a floating point power.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 2.0_f16;
+    /// let abs_difference = (x.powf(2.0) - (x * x)).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powf(self, n: f16) -> f16 {
+        unsafe { intrinsics::powf16(self, n) }
+    }
+
+    /// Returns the square root of a number.
+    ///
+    /// Returns NaN if `self` is a negative number other than `-0.0`.
+    ///
+    /// # Precision
+    ///
+    /// The result of this operation is guaranteed to be the rounded
+    /// infinite-precision result. It is specified by IEEE 754 as `squareRoot`
+    /// and guaranteed not to change.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let positive = 4.0_f16;
+    /// let negative = -4.0_f16;
+    /// let negative_zero = -0.0_f16;
+    ///
+    /// assert_eq!(positive.sqrt(), 2.0);
+    /// assert!(negative.sqrt().is_nan());
+    /// assert!(negative_zero.sqrt() == negative_zero);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn sqrt(self) -> f16 {
+        unsafe { intrinsics::sqrtf16(self) }
+    }
+
+    /// Returns `e^(self)`, (the exponential function).
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let one = 1.0f16;
+    /// // e^1
+    /// let e = one.exp();
+    ///
+    /// // ln(e) - 1 == 0
+    /// let abs_difference = (e.ln() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn exp(self) -> f16 {
+        unsafe { intrinsics::expf16(self) }
+    }
+
+    /// Returns `2^(self)`.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 2.0f16;
+    ///
+    /// // 2^2 - 4 == 0
+    /// let abs_difference = (f.exp2() - 4.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn exp2(self) -> f16 {
+        unsafe { intrinsics::exp2f16(self) }
+    }
+
+    /// Returns the natural logarithm of the number.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let one = 1.0f16;
+    /// // e^1
+    /// let e = one.exp();
+    ///
+    /// // ln(e) - 1 == 0
+    /// let abs_difference = (e.ln() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn ln(self) -> f16 {
+        unsafe { intrinsics::logf16(self) }
+    }
+
+    /// Returns the logarithm of the number with respect to an arbitrary base.
+    ///
+    /// The result might not be correctly rounded owing to implementation details;
+    /// `self.log2()` can produce more accurate results for base 2, and
+    /// `self.log10()` can produce more accurate results for base 10.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let five = 5.0f16;
+    ///
+    /// // log5(5) - 1 == 0
+    /// let abs_difference = (five.log(5.0) - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn log(self, base: f16) -> f16 {
+        self.ln() / base.ln()
+    }
+
+    /// Returns the base 2 logarithm of the number.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let two = 2.0f16;
+    ///
+    /// // log2(2) - 1 == 0
+    /// let abs_difference = (two.log2() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn log2(self) -> f16 {
+        unsafe { intrinsics::log2f16(self) }
+    }
+
+    /// Returns the base 10 logarithm of the number.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let ten = 10.0f16;
+    ///
+    /// // log10(10) - 1 == 0
+    /// let abs_difference = (ten.log10() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn log10(self) -> f16 {
+        unsafe { intrinsics::log10f16(self) }
+    }
+
+    /// Returns the cube root of a number.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `cbrtf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 8.0f16;
+    ///
+    /// // x^(1/3) - 2 == 0
+    /// let abs_difference = (x.cbrt() - 2.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn cbrt(self) -> f16 {
+        (unsafe { cmath::cbrtf(self as f32) }) as f16
+    }
+
+    /// Compute the distance between the origin and a point (`x`, `y`) on the
+    /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a
+    /// right-angle triangle with other sides having length `x.abs()` and
+    /// `y.abs()`.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `hypotf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 2.0f16;
+    /// let y = 3.0f16;
+    ///
+    /// // sqrt(x^2 + y^2)
+    /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn hypot(self, other: f16) -> f16 {
+        (unsafe { cmath::hypotf(self as f32, other as f32) }) as f16
+    }
+
+    /// Computes the sine of a number (in radians).
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = std::f16::consts::FRAC_PI_2;
+    ///
+    /// let abs_difference = (x.sin() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn sin(self) -> f16 {
+        unsafe { intrinsics::sinf16(self) }
+    }
+
+    /// Computes the cosine of a number (in radians).
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 2.0 * std::f16::consts::PI;
+    ///
+    /// let abs_difference = (x.cos() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn cos(self) -> f16 {
+        unsafe { intrinsics::cosf16(self) }
+    }
+
+    /// Computes the tangent of a number (in radians).
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `tanf` from libc on Unix and
+    /// Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = std::f16::consts::FRAC_PI_4;
+    /// let abs_difference = (x.tan() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn tan(self) -> f16 {
+        (unsafe { cmath::tanf(self as f32) }) as f16
+    }
+
+    /// Computes the arcsine of a number. Return value is in radians in
+    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
+    /// [-1, 1].
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `asinf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = std::f16::consts::FRAC_PI_2;
+    ///
+    /// // asin(sin(pi/2))
+    /// let abs_difference = (f.sin().asin() - std::f16::consts::FRAC_PI_2).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arcsin")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn asin(self) -> f16 {
+        (unsafe { cmath::asinf(self as f32) }) as f16
+    }
+
+    /// Computes the arccosine of a number. Return value is in radians in
+    /// the range [0, pi] or NaN if the number is outside the range
+    /// [-1, 1].
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `acosf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = std::f16::consts::FRAC_PI_4;
+    ///
+    /// // acos(cos(pi/4))
+    /// let abs_difference = (f.cos().acos() - std::f16::consts::FRAC_PI_4).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arccos")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn acos(self) -> f16 {
+        (unsafe { cmath::acosf(self as f32) }) as f16
+    }
+
+    /// Computes the arctangent of a number. Return value is in radians in the
+    /// range [-pi/2, pi/2];
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `atanf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let f = 1.0f16;
+    ///
+    /// // atan(tan(1))
+    /// let abs_difference = (f.tan().atan() - 1.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arctan")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn atan(self) -> f16 {
+        (unsafe { cmath::atanf(self as f32) }) as f16
+    }
+
+    /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
+    ///
+    /// * `x = 0`, `y = 0`: `0`
+    /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
+    /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
+    /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `atan2f` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// // Positive angles measured counter-clockwise
+    /// // from positive x axis
+    /// // -pi/4 radians (45 deg clockwise)
+    /// let x1 = 3.0f16;
+    /// let y1 = -3.0f16;
+    ///
+    /// // 3pi/4 radians (135 deg counter-clockwise)
+    /// let x2 = -3.0f16;
+    /// let y2 = 3.0f16;
+    ///
+    /// let abs_difference_1 = (y1.atan2(x1) - (-std::f16::consts::FRAC_PI_4)).abs();
+    /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f16::consts::FRAC_PI_4)).abs();
+    ///
+    /// assert!(abs_difference_1 <= f16::EPSILON);
+    /// assert!(abs_difference_2 <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn atan2(self, other: f16) -> f16 {
+        (unsafe { cmath::atan2f(self as f32, other as f32) }) as f16
+    }
+
+    /// Simultaneously computes the sine and cosine of the number, `x`. Returns
+    /// `(sin(x), cos(x))`.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `(f16::sin(x),
+    /// f16::cos(x))`. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = std::f16::consts::FRAC_PI_4;
+    /// let f = x.sin_cos();
+    ///
+    /// let abs_difference_0 = (f.0 - x.sin()).abs();
+    /// let abs_difference_1 = (f.1 - x.cos()).abs();
+    ///
+    /// assert!(abs_difference_0 <= f16::EPSILON);
+    /// assert!(abs_difference_1 <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "sincos")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    pub fn sin_cos(self) -> (f16, f16) {
+        (self.sin(), self.cos())
+    }
+
+    /// Returns `e^(self) - 1` in a way that is accurate even if the
+    /// number is close to zero.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `expm1f` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 1e-4_f16;
+    ///
+    /// // for very small x, e^x is approximately 1 + x + x^2 / 2
+    /// let approx = x + x * x / 2.0;
+    /// let abs_difference = (x.exp_m1() - approx).abs();
+    ///
+    /// assert!(abs_difference < 1e-4);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn exp_m1(self) -> f16 {
+        (unsafe { cmath::expm1f(self as f32) }) as f16
+    }
+
+    /// Returns `ln(1+n)` (natural logarithm) more accurately than if
+    /// the operations were performed separately.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `log1pf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 1e-4_f16;
+    ///
+    /// // for very small x, ln(1 + x) is approximately x - x^2 / 2
+    /// let approx = x - x * x / 2.0;
+    /// let abs_difference = (x.ln_1p() - approx).abs();
+    ///
+    /// assert!(abs_difference < 1e-4);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "log1p")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn ln_1p(self) -> f16 {
+        (unsafe { cmath::log1pf(self as f32) }) as f16
+    }
+
+    /// Hyperbolic sine function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `sinhf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let e = std::f16::consts::E;
+    /// let x = 1.0f16;
+    ///
+    /// let f = x.sinh();
+    /// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
+    /// let g = ((e * e) - 1.0) / (2.0 * e);
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn sinh(self) -> f16 {
+        (unsafe { cmath::sinhf(self as f32) }) as f16
+    }
+
+    /// Hyperbolic cosine function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `coshf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let e = std::f16::consts::E;
+    /// let x = 1.0f16;
+    /// let f = x.cosh();
+    /// // Solving cosh() at 1 gives this result
+    /// let g = ((e * e) + 1.0) / (2.0 * e);
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// // Same result
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn cosh(self) -> f16 {
+        (unsafe { cmath::coshf(self as f32) }) as f16
+    }
+
+    /// Hyperbolic tangent function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `tanhf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let e = std::f16::consts::E;
+    /// let x = 1.0f16;
+    ///
+    /// let f = x.tanh();
+    /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
+    /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2));
+    /// let abs_difference = (f - g).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn tanh(self) -> f16 {
+        (unsafe { cmath::tanhf(self as f32) }) as f16
+    }
+
+    /// Inverse hyperbolic sine function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 1.0f16;
+    /// let f = x.sinh().asinh();
+    ///
+    /// let abs_difference = (f - x).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arcsinh")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn asinh(self) -> f16 {
+        let ax = self.abs();
+        let ix = 1.0 / ax;
+        (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
+    }
+
+    /// Inverse hyperbolic cosine function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 1.0f16;
+    /// let f = x.cosh().acosh();
+    ///
+    /// let abs_difference = (f - x).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arccosh")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn acosh(self) -> f16 {
+        if self < 1.0 {
+            Self::NAN
+        } else {
+            (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
+        }
+    }
+
+    /// Inverse hyperbolic tangent function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let e = std::f16::consts::E;
+    /// let f = e.tanh().atanh();
+    ///
+    /// let abs_difference = (f - e).abs();
+    ///
+    /// assert!(abs_difference <= 0.01);
+    /// # }
+    /// ```
+    #[inline]
+    #[doc(alias = "arctanh")]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn atanh(self) -> f16 {
+        0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
+    }
+
+    /// Gamma function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `tgammaf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// #![feature(float_gamma)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 5.0f16;
+    ///
+    /// let abs_difference = (x.gamma() - 24.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn gamma(self) -> f16 {
+        (unsafe { cmath::tgammaf(self as f32) }) as f16
+    }
+
+    /// Natural logarithm of the absolute value of the gamma function
+    ///
+    /// The integer part of the tuple indicates the sign of the gamma function.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform,
+    /// Rust version, and can even differ within the same execution from one invocation to the next.
+    ///
+    /// This function currently corresponds to the `lgamma_r` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// #![feature(float_gamma)]
+    /// # #[cfg(reliable_f16_math)] {
+    ///
+    /// let x = 2.0f16;
+    ///
+    /// let abs_difference = (x.ln_gamma().0 - 0.0).abs();
+    ///
+    /// assert!(abs_difference <= f16::EPSILON);
+    /// # }
+    /// ```
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn ln_gamma(self) -> (f16, i32) {
+        let mut signgamp: i32 = 0;
+        let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16;
+        (x, signgamp)
+    }
 }
diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs
index f73bdf68e82..684ee3f3855 100644
--- a/library/std/src/f16/tests.rs
+++ b/library/std/src/f16/tests.rs
@@ -4,11 +4,21 @@
 use crate::f16::consts;
 use crate::num::{FpCategory as Fp, *};
 
-// We run out of precision pretty quickly with f16
-// const F16_APPROX_L1: f16 = 0.001;
-const F16_APPROX_L2: f16 = 0.01;
-// const F16_APPROX_L3: f16 = 0.1;
-const F16_APPROX_L4: f16 = 0.5;
+/// Tolerance for results on the order of 10.0e-2
+#[allow(unused)]
+const TOL_N2: f16 = 0.0001;
+
+/// Tolerance for results on the order of 10.0e+0
+#[allow(unused)]
+const TOL_0: f16 = 0.01;
+
+/// Tolerance for results on the order of 10.0e+2
+#[allow(unused)]
+const TOL_P2: f16 = 0.5;
+
+/// Tolerance for results on the order of 10.0e+4
+#[allow(unused)]
+const TOL_P4: f16 = 10.0;
 
 /// Smallest number
 const TINY_BITS: u16 = 0x1;
@@ -47,7 +57,33 @@ fn test_num_f16() {
     test_num(10f16, 2f16);
 }
 
-// FIXME(f16_f128): add min and max tests when available
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_min_nan() {
+    assert_eq!(f16::NAN.min(2.0), 2.0);
+    assert_eq!(2.0f16.min(f16::NAN), 2.0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_max_nan() {
+    assert_eq!(f16::NAN.max(2.0), 2.0);
+    assert_eq!(2.0f16.max(f16::NAN), 2.0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_minimum() {
+    assert!(f16::NAN.minimum(2.0).is_nan());
+    assert!(2.0f16.minimum(f16::NAN).is_nan());
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_maximum() {
+    assert!(f16::NAN.maximum(2.0).is_nan());
+    assert!(2.0f16.maximum(f16::NAN).is_nan());
+}
 
 #[test]
 fn test_nan() {
@@ -197,9 +233,100 @@ fn test_classify() {
     assert_eq!(1e-5f16.classify(), Fp::Subnormal);
 }
 
-// FIXME(f16_f128): add missing math functions when available
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_floor() {
+    assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.3f16.floor(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.5f16.floor(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.7f16.floor(), 1.0f16, TOL_0);
+    assert_approx_eq!(0.0f16.floor(), 0.0f16, TOL_0);
+    assert_approx_eq!((-0.0f16).floor(), -0.0f16, TOL_0);
+    assert_approx_eq!((-1.0f16).floor(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.3f16).floor(), -2.0f16, TOL_0);
+    assert_approx_eq!((-1.5f16).floor(), -2.0f16, TOL_0);
+    assert_approx_eq!((-1.7f16).floor(), -2.0f16, TOL_0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_ceil() {
+    assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.3f16.ceil(), 2.0f16, TOL_0);
+    assert_approx_eq!(1.5f16.ceil(), 2.0f16, TOL_0);
+    assert_approx_eq!(1.7f16.ceil(), 2.0f16, TOL_0);
+    assert_approx_eq!(0.0f16.ceil(), 0.0f16, TOL_0);
+    assert_approx_eq!((-0.0f16).ceil(), -0.0f16, TOL_0);
+    assert_approx_eq!((-1.0f16).ceil(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.3f16).ceil(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.5f16).ceil(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.7f16).ceil(), -1.0f16, TOL_0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_round() {
+    assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0);
+    assert_approx_eq!(1.0f16.round(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.3f16.round(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.5f16.round(), 2.0f16, TOL_0);
+    assert_approx_eq!(1.7f16.round(), 2.0f16, TOL_0);
+    assert_approx_eq!(0.0f16.round(), 0.0f16, TOL_0);
+    assert_approx_eq!((-0.0f16).round(), -0.0f16, TOL_0);
+    assert_approx_eq!((-1.0f16).round(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.3f16).round(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.5f16).round(), -2.0f16, TOL_0);
+    assert_approx_eq!((-1.7f16).round(), -2.0f16, TOL_0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_round_ties_even() {
+    assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0);
+    assert_approx_eq!(1.0f16.round_ties_even(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.3f16.round_ties_even(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.5f16.round_ties_even(), 2.0f16, TOL_0);
+    assert_approx_eq!(1.7f16.round_ties_even(), 2.0f16, TOL_0);
+    assert_approx_eq!(0.0f16.round_ties_even(), 0.0f16, TOL_0);
+    assert_approx_eq!((-0.0f16).round_ties_even(), -0.0f16, TOL_0);
+    assert_approx_eq!((-1.0f16).round_ties_even(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.3f16).round_ties_even(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.5f16).round_ties_even(), -2.0f16, TOL_0);
+    assert_approx_eq!((-1.7f16).round_ties_even(), -2.0f16, TOL_0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_trunc() {
+    assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.3f16.trunc(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.5f16.trunc(), 1.0f16, TOL_0);
+    assert_approx_eq!(1.7f16.trunc(), 1.0f16, TOL_0);
+    assert_approx_eq!(0.0f16.trunc(), 0.0f16, TOL_0);
+    assert_approx_eq!((-0.0f16).trunc(), -0.0f16, TOL_0);
+    assert_approx_eq!((-1.0f16).trunc(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.3f16).trunc(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.5f16).trunc(), -1.0f16, TOL_0);
+    assert_approx_eq!((-1.7f16).trunc(), -1.0f16, TOL_0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_fract() {
+    assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0);
+    assert_approx_eq!(1.3f16.fract(), 0.3f16, TOL_0);
+    assert_approx_eq!(1.5f16.fract(), 0.5f16, TOL_0);
+    assert_approx_eq!(1.7f16.fract(), 0.7f16, TOL_0);
+    assert_approx_eq!(0.0f16.fract(), 0.0f16, TOL_0);
+    assert_approx_eq!((-0.0f16).fract(), -0.0f16, TOL_0);
+    assert_approx_eq!((-1.0f16).fract(), -0.0f16, TOL_0);
+    assert_approx_eq!((-1.3f16).fract(), -0.3f16, TOL_0);
+    assert_approx_eq!((-1.5f16).fract(), -0.5f16, TOL_0);
+    assert_approx_eq!((-1.7f16).fract(), -0.7f16, TOL_0);
+}
 
 #[test]
+#[cfg(reliable_f16_math)]
 fn test_abs() {
     assert_eq!(f16::INFINITY.abs(), f16::INFINITY);
     assert_eq!(1f16.abs(), 1f16);
@@ -299,6 +426,24 @@ fn test_next_down() {
 }
 
 #[test]
+#[cfg(reliable_f16_math)]
+fn test_mul_add() {
+    let nan: f16 = f16::NAN;
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    assert_approx_eq!(12.3f16.mul_add(4.5, 6.7), 62.05, TOL_P2);
+    assert_approx_eq!((-12.3f16).mul_add(-4.5, -6.7), 48.65, TOL_P2);
+    assert_approx_eq!(0.0f16.mul_add(8.9, 1.2), 1.2, TOL_0);
+    assert_approx_eq!(3.4f16.mul_add(-0.0, 5.6), 5.6, TOL_0);
+    assert!(nan.mul_add(7.8, 9.0).is_nan());
+    assert_eq!(inf.mul_add(7.8, 9.0), inf);
+    assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
+    assert_eq!(8.9f16.mul_add(inf, 3.2), inf);
+    assert_eq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
 fn test_recip() {
     let nan: f16 = f16::NAN;
     let inf: f16 = f16::INFINITY;
@@ -307,20 +452,166 @@ fn test_recip() {
     assert_eq!(2.0f16.recip(), 0.5);
     assert_eq!((-0.4f16).recip(), -2.5);
     assert_eq!(0.0f16.recip(), inf);
+    assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4);
     assert!(nan.recip().is_nan());
     assert_eq!(inf.recip(), 0.0);
     assert_eq!(neg_inf.recip(), 0.0);
 }
 
 #[test]
+#[cfg(reliable_f16_math)]
+fn test_powi() {
+    // FIXME(llvm19): LLVM misoptimizes `powi.f16`
+    // <https://github.com/llvm/llvm-project/issues/98665>
+    // let nan: f16 = f16::NAN;
+    // let inf: f16 = f16::INFINITY;
+    // let neg_inf: f16 = f16::NEG_INFINITY;
+    // assert_eq!(1.0f16.powi(1), 1.0);
+    // assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0);
+    // assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2);
+    // assert_eq!(8.3f16.powi(0), 1.0);
+    // assert!(nan.powi(2).is_nan());
+    // assert_eq!(inf.powi(3), inf);
+    // assert_eq!(neg_inf.powi(2), inf);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_powf() {
+    let nan: f16 = f16::NAN;
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    assert_eq!(1.0f16.powf(1.0), 1.0);
+    assert_approx_eq!(3.4f16.powf(4.5), 246.408183, TOL_P2);
+    assert_approx_eq!(2.7f16.powf(-3.2), 0.041652, TOL_N2);
+    assert_approx_eq!((-3.1f16).powf(2.0), 9.61, TOL_P2);
+    assert_approx_eq!(5.9f16.powf(-2.0), 0.028727, TOL_N2);
+    assert_eq!(8.3f16.powf(0.0), 1.0);
+    assert!(nan.powf(2.0).is_nan());
+    assert_eq!(inf.powf(2.0), inf);
+    assert_eq!(neg_inf.powf(3.0), neg_inf);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_sqrt_domain() {
+    assert!(f16::NAN.sqrt().is_nan());
+    assert!(f16::NEG_INFINITY.sqrt().is_nan());
+    assert!((-1.0f16).sqrt().is_nan());
+    assert_eq!((-0.0f16).sqrt(), -0.0);
+    assert_eq!(0.0f16.sqrt(), 0.0);
+    assert_eq!(1.0f16.sqrt(), 1.0);
+    assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_exp() {
+    assert_eq!(1.0, 0.0f16.exp());
+    assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0);
+    assert_approx_eq!(148.413159, 5.0f16.exp(), TOL_0);
+
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    let nan: f16 = f16::NAN;
+    assert_eq!(inf, inf.exp());
+    assert_eq!(0.0, neg_inf.exp());
+    assert!(nan.exp().is_nan());
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_exp2() {
+    assert_eq!(32.0, 5.0f16.exp2());
+    assert_eq!(1.0, 0.0f16.exp2());
+
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    let nan: f16 = f16::NAN;
+    assert_eq!(inf, inf.exp2());
+    assert_eq!(0.0, neg_inf.exp2());
+    assert!(nan.exp2().is_nan());
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_ln() {
+    let nan: f16 = f16::NAN;
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    assert_approx_eq!(1.0f16.exp().ln(), 1.0, TOL_0);
+    assert!(nan.ln().is_nan());
+    assert_eq!(inf.ln(), inf);
+    assert!(neg_inf.ln().is_nan());
+    assert!((-2.3f16).ln().is_nan());
+    assert_eq!((-0.0f16).ln(), neg_inf);
+    assert_eq!(0.0f16.ln(), neg_inf);
+    assert_approx_eq!(4.0f16.ln(), 1.386294, TOL_0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_log() {
+    let nan: f16 = f16::NAN;
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    assert_eq!(10.0f16.log(10.0), 1.0);
+    assert_approx_eq!(2.3f16.log(3.5), 0.664858, TOL_0);
+    assert_eq!(1.0f16.exp().log(1.0f16.exp()), 1.0);
+    assert!(1.0f16.log(1.0).is_nan());
+    assert!(1.0f16.log(-13.9).is_nan());
+    assert!(nan.log(2.3).is_nan());
+    assert_eq!(inf.log(10.0), inf);
+    assert!(neg_inf.log(8.8).is_nan());
+    assert!((-2.3f16).log(0.1).is_nan());
+    assert_eq!((-0.0f16).log(2.0), neg_inf);
+    assert_eq!(0.0f16.log(7.0), neg_inf);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_log2() {
+    let nan: f16 = f16::NAN;
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    assert_approx_eq!(10.0f16.log2(), 3.321928, TOL_0);
+    assert_approx_eq!(2.3f16.log2(), 1.201634, TOL_0);
+    assert_approx_eq!(1.0f16.exp().log2(), 1.442695, TOL_0);
+    assert!(nan.log2().is_nan());
+    assert_eq!(inf.log2(), inf);
+    assert!(neg_inf.log2().is_nan());
+    assert!((-2.3f16).log2().is_nan());
+    assert_eq!((-0.0f16).log2(), neg_inf);
+    assert_eq!(0.0f16.log2(), neg_inf);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_log10() {
+    let nan: f16 = f16::NAN;
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    assert_eq!(10.0f16.log10(), 1.0);
+    assert_approx_eq!(2.3f16.log10(), 0.361728, TOL_0);
+    assert_approx_eq!(1.0f16.exp().log10(), 0.434294, TOL_0);
+    assert_eq!(1.0f16.log10(), 0.0);
+    assert!(nan.log10().is_nan());
+    assert_eq!(inf.log10(), inf);
+    assert!(neg_inf.log10().is_nan());
+    assert!((-2.3f16).log10().is_nan());
+    assert_eq!((-0.0f16).log10(), neg_inf);
+    assert_eq!(0.0f16.log10(), neg_inf);
+}
+
+#[test]
 fn test_to_degrees() {
     let pi: f16 = consts::PI;
     let nan: f16 = f16::NAN;
     let inf: f16 = f16::INFINITY;
     let neg_inf: f16 = f16::NEG_INFINITY;
     assert_eq!(0.0f16.to_degrees(), 0.0);
-    assert_approx_eq!((-5.8f16).to_degrees(), -332.315521);
-    assert_approx_eq!(pi.to_degrees(), 180.0, F16_APPROX_L4);
+    assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2);
+    assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2);
     assert!(nan.to_degrees().is_nan());
     assert_eq!(inf.to_degrees(), inf);
     assert_eq!(neg_inf.to_degrees(), neg_inf);
@@ -334,15 +625,113 @@ fn test_to_radians() {
     let inf: f16 = f16::INFINITY;
     let neg_inf: f16 = f16::NEG_INFINITY;
     assert_eq!(0.0f16.to_radians(), 0.0);
-    assert_approx_eq!(154.6f16.to_radians(), 2.698279);
-    assert_approx_eq!((-332.31f16).to_radians(), -5.799903);
-    assert_approx_eq!(180.0f16.to_radians(), pi, F16_APPROX_L2);
+    assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0);
+    assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0);
+    assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0);
     assert!(nan.to_radians().is_nan());
     assert_eq!(inf.to_radians(), inf);
     assert_eq!(neg_inf.to_radians(), neg_inf);
 }
 
 #[test]
+#[cfg(reliable_f16_math)]
+fn test_asinh() {
+    assert_eq!(0.0f16.asinh(), 0.0f16);
+    assert_eq!((-0.0f16).asinh(), -0.0f16);
+
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    let nan: f16 = f16::NAN;
+    assert_eq!(inf.asinh(), inf);
+    assert_eq!(neg_inf.asinh(), neg_inf);
+    assert!(nan.asinh().is_nan());
+    assert!((-0.0f16).asinh().is_sign_negative());
+    // issue 63271
+    assert_approx_eq!(2.0f16.asinh(), 1.443635475178810342493276740273105f16, TOL_0);
+    assert_approx_eq!((-2.0f16).asinh(), -1.443635475178810342493276740273105f16, TOL_0);
+    // regression test for the catastrophic cancellation fixed in 72486
+    assert_approx_eq!((-200.0f16).asinh(), -5.991470797049389, TOL_0);
+
+    // test for low accuracy from issue 104548
+    assert_approx_eq!(10.0f16, 10.0f16.sinh().asinh(), TOL_0);
+    // mul needed for approximate comparison to be meaningful
+    assert_approx_eq!(1.0f16, 1e-3f16.sinh().asinh() * 1e3f16, TOL_0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_acosh() {
+    assert_eq!(1.0f16.acosh(), 0.0f16);
+    assert!(0.999f16.acosh().is_nan());
+
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    let nan: f16 = f16::NAN;
+    assert_eq!(inf.acosh(), inf);
+    assert!(neg_inf.acosh().is_nan());
+    assert!(nan.acosh().is_nan());
+    assert_approx_eq!(2.0f16.acosh(), 1.31695789692481670862504634730796844f16, TOL_0);
+    assert_approx_eq!(3.0f16.acosh(), 1.76274717403908605046521864995958461f16, TOL_0);
+
+    // test for low accuracy from issue 104548
+    assert_approx_eq!(10.0f16, 10.0f16.cosh().acosh(), TOL_P2);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_atanh() {
+    assert_eq!(0.0f16.atanh(), 0.0f16);
+    assert_eq!((-0.0f16).atanh(), -0.0f16);
+
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    let nan: f16 = f16::NAN;
+    assert_eq!(1.0f16.atanh(), inf);
+    assert_eq!((-1.0f16).atanh(), neg_inf);
+    assert!(2f16.atanh().atanh().is_nan());
+    assert!((-2f16).atanh().atanh().is_nan());
+    assert!(inf.atanh().is_nan());
+    assert!(neg_inf.atanh().is_nan());
+    assert!(nan.atanh().is_nan());
+    assert_approx_eq!(0.5f16.atanh(), 0.54930614433405484569762261846126285f16, TOL_0);
+    assert_approx_eq!((-0.5f16).atanh(), -0.54930614433405484569762261846126285f16, TOL_0);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_gamma() {
+    // precision can differ among platforms
+    assert_approx_eq!(1.0f16.gamma(), 1.0f16, TOL_0);
+    assert_approx_eq!(2.0f16.gamma(), 1.0f16, TOL_0);
+    assert_approx_eq!(3.0f16.gamma(), 2.0f16, TOL_0);
+    assert_approx_eq!(4.0f16.gamma(), 6.0f16, TOL_0);
+    assert_approx_eq!(5.0f16.gamma(), 24.0f16, TOL_0);
+    assert_approx_eq!(0.5f16.gamma(), consts::PI.sqrt(), TOL_0);
+    assert_approx_eq!((-0.5f16).gamma(), -2.0 * consts::PI.sqrt(), TOL_0);
+    assert_eq!(0.0f16.gamma(), f16::INFINITY);
+    assert_eq!((-0.0f16).gamma(), f16::NEG_INFINITY);
+    assert!((-1.0f16).gamma().is_nan());
+    assert!((-2.0f16).gamma().is_nan());
+    assert!(f16::NAN.gamma().is_nan());
+    assert!(f16::NEG_INFINITY.gamma().is_nan());
+    assert_eq!(f16::INFINITY.gamma(), f16::INFINITY);
+    assert_eq!(171.71f16.gamma(), f16::INFINITY);
+}
+
+#[test]
+#[cfg(reliable_f16_math)]
+fn test_ln_gamma() {
+    assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0);
+    assert_eq!(1.0f16.ln_gamma().1, 1);
+    assert_approx_eq!(2.0f16.ln_gamma().0, 0.0f16, TOL_0);
+    assert_eq!(2.0f16.ln_gamma().1, 1);
+    assert_approx_eq!(3.0f16.ln_gamma().0, 2.0f16.ln(), TOL_0);
+    assert_eq!(3.0f16.ln_gamma().1, 1);
+    assert_approx_eq!((-0.5f16).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_0);
+    assert_eq!((-0.5f16).ln_gamma().1, -1);
+}
+
+#[test]
 fn test_real_consts() {
     // FIXME(f16_f128): add math tests when available
     use super::consts;
@@ -355,29 +744,34 @@ fn test_real_consts() {
     let frac_pi_8: f16 = consts::FRAC_PI_8;
     let frac_1_pi: f16 = consts::FRAC_1_PI;
     let frac_2_pi: f16 = consts::FRAC_2_PI;
-    // let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI;
-    // let sqrt2: f16 = consts::SQRT_2;
-    // let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2;
-    // let e: f16 = consts::E;
-    // let log2_e: f16 = consts::LOG2_E;
-    // let log10_e: f16 = consts::LOG10_E;
-    // let ln_2: f16 = consts::LN_2;
-    // let ln_10: f16 = consts::LN_10;
-
-    assert_approx_eq!(frac_pi_2, pi / 2f16);
-    assert_approx_eq!(frac_pi_3, pi / 3f16);
-    assert_approx_eq!(frac_pi_4, pi / 4f16);
-    assert_approx_eq!(frac_pi_6, pi / 6f16);
-    assert_approx_eq!(frac_pi_8, pi / 8f16);
-    assert_approx_eq!(frac_1_pi, 1f16 / pi);
-    assert_approx_eq!(frac_2_pi, 2f16 / pi);
-    // assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt());
-    // assert_approx_eq!(sqrt2, 2f16.sqrt());
-    // assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt());
-    // assert_approx_eq!(log2_e, e.log2());
-    // assert_approx_eq!(log10_e, e.log10());
-    // assert_approx_eq!(ln_2, 2f16.ln());
-    // assert_approx_eq!(ln_10, 10f16.ln());
+
+    assert_approx_eq!(frac_pi_2, pi / 2f16, TOL_0);
+    assert_approx_eq!(frac_pi_3, pi / 3f16, TOL_0);
+    assert_approx_eq!(frac_pi_4, pi / 4f16, TOL_0);
+    assert_approx_eq!(frac_pi_6, pi / 6f16, TOL_0);
+    assert_approx_eq!(frac_pi_8, pi / 8f16, TOL_0);
+    assert_approx_eq!(frac_1_pi, 1f16 / pi, TOL_0);
+    assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0);
+
+    #[cfg(reliable_f16_math)]
+    {
+        let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI;
+        let sqrt2: f16 = consts::SQRT_2;
+        let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2;
+        let e: f16 = consts::E;
+        let log2_e: f16 = consts::LOG2_E;
+        let log10_e: f16 = consts::LOG10_E;
+        let ln_2: f16 = consts::LN_2;
+        let ln_10: f16 = consts::LN_10;
+
+        assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt(), TOL_0);
+        assert_approx_eq!(sqrt2, 2f16.sqrt(), TOL_0);
+        assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt(), TOL_0);
+        assert_approx_eq!(log2_e, e.log2(), TOL_0);
+        assert_approx_eq!(log10_e, e.log10(), TOL_0);
+        assert_approx_eq!(ln_2, 2f16.ln(), TOL_0);
+        assert_approx_eq!(ln_10, 10f16.ln(), TOL_0);
+    }
 }
 
 #[test]
@@ -386,10 +780,10 @@ fn test_float_bits_conv() {
     assert_eq!((12.5f16).to_bits(), 0x4a40);
     assert_eq!((1337f16).to_bits(), 0x6539);
     assert_eq!((-14.25f16).to_bits(), 0xcb20);
-    assert_approx_eq!(f16::from_bits(0x3c00), 1.0);
-    assert_approx_eq!(f16::from_bits(0x4a40), 12.5);
-    assert_approx_eq!(f16::from_bits(0x6539), 1337.0);
-    assert_approx_eq!(f16::from_bits(0xcb20), -14.25);
+    assert_approx_eq!(f16::from_bits(0x3c00), 1.0, TOL_0);
+    assert_approx_eq!(f16::from_bits(0x4a40), 12.5, TOL_0);
+    assert_approx_eq!(f16::from_bits(0x6539), 1337.0, TOL_P4);
+    assert_approx_eq!(f16::from_bits(0xcb20), -14.25, TOL_0);
 
     // Check that NaNs roundtrip their bits regardless of signaling-ness
     let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1;
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index f11dd50c5e2..0b12e5777c8 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -94,6 +94,40 @@ impl<R: Read> BufReader<R> {
     pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
         BufReader { inner, buf: Buffer::with_capacity(capacity) }
     }
+
+    /// Attempt to look ahead `n` bytes.
+    ///
+    /// `n` must be less than `capacity`.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// #![feature(bufreader_peek)]
+    /// use std::io::{Read, BufReader};
+    ///
+    /// let mut bytes = &b"oh, hello"[..];
+    /// let mut rdr = BufReader::with_capacity(6, &mut bytes);
+    /// assert_eq!(rdr.peek(2).unwrap(), b"oh");
+    /// let mut buf = [0; 4];
+    /// rdr.read(&mut buf[..]).unwrap();
+    /// assert_eq!(&buf, b"oh, ");
+    /// assert_eq!(rdr.peek(2).unwrap(), b"he");
+    /// let mut s = String::new();
+    /// rdr.read_to_string(&mut s).unwrap();
+    /// assert_eq!(&s, "hello");
+    /// ```
+    #[unstable(feature = "bufreader_peek", issue = "128405")]
+    pub fn peek(&mut self, n: usize) -> io::Result<&[u8]> {
+        assert!(n <= self.capacity());
+        while n > self.buf.buffer().len() {
+            if self.buf.pos() > 0 {
+                self.buf.backshift();
+            }
+            self.buf.read_more(&mut self.inner)?;
+            debug_assert_eq!(self.buf.pos(), 0);
+        }
+        Ok(&self.buf.buffer()[..n])
+    }
 }
 
 impl<R: ?Sized> BufReader<R> {
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 796137c0123..ccd67fafb45 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -97,6 +97,27 @@ impl Buffer {
         self.pos = self.pos.saturating_sub(amt);
     }
 
+    /// Read more bytes into the buffer without discarding any of its contents
+    pub fn read_more(&mut self, mut reader: impl Read) -> io::Result<()> {
+        let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]);
+        let old_init = self.initialized - self.pos;
+        unsafe {
+            buf.set_init(old_init);
+        }
+        reader.read_buf(buf.unfilled())?;
+        self.filled += buf.len();
+        self.initialized += buf.init_len() - old_init;
+        Ok(())
+    }
+
+    /// Remove bytes that have already been read from the buffer.
+    pub fn backshift(&mut self) {
+        self.buf.copy_within(self.pos.., 0);
+        self.initialized -= self.pos;
+        self.filled -= self.pos;
+        self.pos = 0;
+    }
+
     #[inline]
     pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> {
         // If we've reached the end of our internal buffer then we need to fetch
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index c82228fca4b..9f4d244b547 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -155,7 +155,7 @@ mod break_keyword {}
 /// const WORDS: &str = "hello convenience!";
 /// ```
 ///
-/// `const` items looks remarkably similar to `static` items, which introduces some confusion as
+/// `const` items look remarkably similar to `static` items, which introduces some confusion as
 /// to which one should be used at which times. To put it simply, constants are inlined wherever
 /// they're used, making using them identical to simply replacing the name of the `const` with its
 /// value. Static variables, on the other hand, point to a single location in memory, which all
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 37ba7e7065d..93a74ef739b 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -269,13 +269,10 @@
 #![cfg_attr(any(windows, target_os = "uefi"), feature(round_char_boundary))]
 #![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))]
 #![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))]
-#![cfg_attr(
-    all(any(target_arch = "x86_64", target_arch = "x86"), target_os = "uefi"),
-    feature(stdarch_x86_has_cpuid)
-)]
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![feature(alloc_error_handler)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
@@ -303,7 +300,6 @@
 #![feature(link_cfg)]
 #![feature(linkage)]
 #![feature(macro_metavar_expr_concat)]
-#![feature(min_exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(must_not_suspend)]
 #![feature(needs_panic_runtime)]
@@ -343,6 +339,7 @@
 #![feature(maybe_uninit_write_slice)]
 #![feature(panic_can_unwind)]
 #![feature(panic_internals)]
+#![feature(pin_coerce_unsized_trait)]
 #![feature(pointer_is_aligned_to)]
 #![feature(portable_simd)]
 #![feature(prelude_2024)]
@@ -589,7 +586,7 @@ pub mod net;
 pub mod num;
 pub mod os;
 pub mod panic;
-#[unstable(feature = "core_pattern_types", issue = "none")]
+#[unstable(feature = "core_pattern_types", issue = "123646")]
 pub mod pat;
 pub mod path;
 #[unstable(feature = "anonymous_pipe", issue = "127154")]
@@ -671,7 +668,6 @@ mod panicking;
 #[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)]
 mod backtrace_rs;
 
-// Re-export macros defined in core.
 #[unstable(feature = "cfg_match", issue = "115585")]
 pub use core::cfg_match;
 #[unstable(
@@ -690,6 +686,7 @@ pub use core::{
     env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
     module_path, option_env, stringify, trace_macros,
 };
+// Re-export macros defined in core.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::{
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index ba519afc62b..1b0d7f3dbf2 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -382,7 +382,7 @@ macro_rules! assert_approx_eq {
         let diff = (*a - *b).abs();
         assert!(
             diff < $lim,
-            "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, actual {diff:?})",
+            "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})",
             lim = $lim
         );
     }};
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 1e6ecd7d7a6..0d99d5492a2 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -138,6 +138,7 @@ pub trait IntoRawFd {
     /// let raw_fd: RawFd = f.into_raw_fd();
     /// # Ok::<(), io::Error>(())
     /// ```
+    #[must_use = "losing the raw file descriptor may leak resources"]
     #[stable(feature = "into_raw_os", since = "1.4.0")]
     fn into_raw_fd(self) -> RawFd;
 }
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index 9e89d9fbc1b..2d18f339615 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -342,6 +342,7 @@ pub trait IntoRawFd {
     /// This function **transfers ownership** of the underlying file descriptor
     /// to the caller. Callers are then the unique owners of the file descriptor
     /// and must close the descriptor once it's no longer needed.
+    #[must_use = "losing the raw file descriptor may leak resources"]
     fn into_raw_fd(self) -> RawFd;
 }
 
diff --git a/library/std/src/os/vxworks/mod.rs b/library/std/src/os/vxworks/mod.rs
index 0a7ac641dd3..b09aa72f726 100644
--- a/library/std/src/os/vxworks/mod.rs
+++ b/library/std/src/os/vxworks/mod.rs
@@ -1,6 +1,7 @@
 //! VxWorks-specific definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 pub mod fs;
 pub mod raw;
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
index 4ba07e3d2af..6658248d574 100644
--- a/library/std/src/os/windows/io/raw.rs
+++ b/library/std/src/os/windows/io/raw.rs
@@ -85,6 +85,7 @@ pub trait IntoRawHandle {
     /// However, transferring ownership is not strictly required. Use a
     /// `Into<OwnedHandle>::into` implementation for an API which strictly
     /// transfers ownership.
+    #[must_use = "losing the raw handle may leak resources"]
     #[stable(feature = "into_raw_os", since = "1.4.0")]
     fn into_raw_handle(self) -> RawHandle;
 }
@@ -228,6 +229,7 @@ pub trait IntoRawSocket {
     /// However, transferring ownership is not strictly required. Use a
     /// `Into<OwnedSocket>::into` implementation for an API which strictly
     /// transfers ownership.
+    #[must_use = "losing the raw socket may leak resources"]
     #[stable(feature = "into_raw_os", since = "1.4.0")]
     fn into_raw_socket(self) -> RawSocket;
 }
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 2ca9256715c..4c496ade81c 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -463,11 +463,10 @@ static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0);
 /// environment variable; see the details in [`get_backtrace_style`].
 #[unstable(feature = "panic_backtrace_config", issue = "93346")]
 pub fn set_backtrace_style(style: BacktraceStyle) {
-    if !cfg!(feature = "backtrace") {
-        // If the `backtrace` feature of this crate isn't enabled, skip setting.
-        return;
+    if cfg!(feature = "backtrace") {
+        // If the `backtrace` feature of this crate is enabled, set the backtrace style.
+        SHOULD_CAPTURE.store(style.as_u8(), Ordering::Release);
     }
-    SHOULD_CAPTURE.store(style.as_u8(), Ordering::Release);
 }
 
 /// Checks whether the standard library's panic hook will capture and print a
@@ -503,21 +502,13 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> {
         return Some(style);
     }
 
-    let format = crate::env::var_os("RUST_BACKTRACE")
-        .map(|x| {
-            if &x == "0" {
-                BacktraceStyle::Off
-            } else if &x == "full" {
-                BacktraceStyle::Full
-            } else {
-                BacktraceStyle::Short
-            }
-        })
-        .unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT {
-            BacktraceStyle::Full
-        } else {
-            BacktraceStyle::Off
-        });
+    let format = match crate::env::var_os("RUST_BACKTRACE") {
+        Some(x) if &x == "0" => BacktraceStyle::Off,
+        Some(x) if &x == "full" => BacktraceStyle::Full,
+        Some(_) => BacktraceStyle::Short,
+        None if crate::sys::FULL_BACKTRACE_DEFAULT => BacktraceStyle::Full,
+        None => BacktraceStyle::Off,
+    };
     set_backtrace_style(format);
     Some(format)
 }
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
index 12bb0fbf050..37a2e41641a 100644
--- a/library/std/src/sync/rwlock/tests.rs
+++ b/library/std/src/sync/rwlock/tests.rs
@@ -21,6 +21,10 @@ fn smoke() {
 }
 
 #[test]
+// FIXME: On macOS we use a provenance-incorrect implementation and Miri
+// catches that issue with a chance of around 1/1000.
+// See <https://github.com/rust-lang/rust/issues/121950> for details.
+#[cfg_attr(all(miri, target_os = "macos"), ignore)]
 fn frob() {
     const N: u32 = 10;
     const M: usize = if cfg!(miri) { 100 } else { 1000 };
diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs
index 99df503b82d..2997e908fa1 100644
--- a/library/std/src/sys/cmath.rs
+++ b/library/std/src/sys/cmath.rs
@@ -28,6 +28,21 @@ extern "C" {
     pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
     pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
 
+    pub fn acosf128(n: f128) -> f128;
+    pub fn asinf128(n: f128) -> f128;
+    pub fn atanf128(n: f128) -> f128;
+    pub fn atan2f128(a: f128, b: f128) -> f128;
+    pub fn cbrtf128(n: f128) -> f128;
+    pub fn coshf128(n: f128) -> f128;
+    pub fn expm1f128(n: f128) -> f128;
+    pub fn hypotf128(x: f128, y: f128) -> f128;
+    pub fn log1pf128(n: f128) -> f128;
+    pub fn sinhf128(n: f128) -> f128;
+    pub fn tanf128(n: f128) -> f128;
+    pub fn tanhf128(n: f128) -> f128;
+    pub fn tgammaf128(n: f128) -> f128;
+    pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
+
     cfg_if::cfg_if! {
     if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
         pub fn acosf(n: f32) -> f32;
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
index 29809525739..5069ab82ccc 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
@@ -8,6 +8,7 @@ use crate::cell::UnsafeCell;
 use crate::convert::TryInto;
 use crate::mem::{self, ManuallyDrop};
 use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut};
+use crate::pin::PinCoerceUnsized;
 use crate::ptr::{self, NonNull};
 use crate::slice::SliceIndex;
 use crate::{cmp, intrinsics, slice};
@@ -751,6 +752,9 @@ where
 #[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
 
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized> PinCoerceUnsized for UserRef<T> {}
+
 #[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T, I> Index<I> for UserRef<[T]>
 where
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index df65d1cc8fc..cecd53c352c 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -1,4 +1,5 @@
 #![cfg_attr(test, allow(dead_code))] // why is this necessary?
+
 use super::abi::usercalls;
 use super::unsupported;
 use crate::ffi::CStr;
diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs
index a97d69f997b..495ff2dc930 100644
--- a/library/std/src/sys/pal/uefi/time.rs
+++ b/library/std/src/sys/pal/uefi/time.rs
@@ -175,10 +175,6 @@ pub(crate) mod instant_internal {
 
     #[cfg(target_arch = "x86_64")]
     fn timestamp_rdtsc() -> Option<Duration> {
-        if !crate::arch::x86_64::has_cpuid() {
-            return None;
-        }
-
         static FREQUENCY: crate::sync::OnceLock<u64> = crate::sync::OnceLock::new();
 
         // Get Frequency in Mhz
@@ -200,10 +196,6 @@ pub(crate) mod instant_internal {
 
     #[cfg(target_arch = "x86")]
     fn timestamp_rdtsc() -> Option<Duration> {
-        if !crate::arch::x86::has_cpuid() {
-            return None;
-        }
-
         static FREQUENCY: crate::sync::OnceLock<u64> = crate::sync::OnceLock::new();
 
         let freq = FREQUENCY
diff --git a/library/std/src/sys/pal/unix/kernel_copy.rs b/library/std/src/sys/pal/unix/kernel_copy.rs
index 652b2e1feb7..a671383cb79 100644
--- a/library/std/src/sys/pal/unix/kernel_copy.rs
+++ b/library/std/src/sys/pal/unix/kernel_copy.rs
@@ -60,6 +60,7 @@ use crate::net::TcpStream;
 use crate::os::unix::fs::FileTypeExt;
 use crate::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 use crate::os::unix::net::UnixStream;
+use crate::pipe::{PipeReader, PipeWriter};
 use crate::process::{ChildStderr, ChildStdin, ChildStdout};
 use crate::ptr;
 use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
@@ -405,6 +406,30 @@ impl CopyWrite for &UnixStream {
     }
 }
 
+impl CopyRead for PipeReader {
+    fn properties(&self) -> CopyParams {
+        CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
+    }
+}
+
+impl CopyRead for &PipeReader {
+    fn properties(&self) -> CopyParams {
+        CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
+    }
+}
+
+impl CopyWrite for PipeWriter {
+    fn properties(&self) -> CopyParams {
+        CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
+    }
+}
+
+impl CopyWrite for &PipeWriter {
+    fn properties(&self) -> CopyParams {
+        CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
+    }
+}
+
 impl CopyWrite for ChildStdin {
     fn properties(&self) -> CopyParams {
         CopyParams(FdMeta::Pipe, Some(self.as_raw_fd()))
diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs
index 8762af614f1..f0ebc767bad 100644
--- a/library/std/src/sys/pal/unix/pipe.rs
+++ b/library/std/src/sys/pal/unix/pipe.rs
@@ -47,6 +47,8 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
 }
 
 impl AnonPipe {
+    #[allow(dead_code)]
+    // FIXME: This function seems legitimately unused.
     pub fn try_clone(&self) -> io::Result<Self> {
         self.0.duplicate().map(Self)
     }
@@ -85,6 +87,8 @@ impl AnonPipe {
         self.0.is_write_vectored()
     }
 
+    #[allow(dead_code)]
+    // FIXME: This function seems legitimately unused.
     pub fn as_file_desc(&self) -> &FileDesc {
         &self.0
     }
diff --git a/library/std/src/sys/pal/unix/process/process_unix/tests.rs b/library/std/src/sys/pal/unix/process/process_unix/tests.rs
index e5e1f956bc3..f4d6ac6b4e3 100644
--- a/library/std/src/sys/pal/unix/process/process_unix/tests.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix/tests.rs
@@ -24,7 +24,20 @@ fn exitstatus_display_tests() {
     // The purpose of this test is to test our string formatting, not our understanding of the wait
     // status magic numbers. So restrict these to Linux.
     if cfg!(target_os = "linux") {
+        #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
+        t(0x0137f, "stopped (not terminated) by signal: 19 (SIGPWR)");
+
+        #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
+        t(0x0137f, "stopped (not terminated) by signal: 19 (SIGCONT)");
+
+        #[cfg(not(any(
+            target_arch = "mips",
+            target_arch = "mips64",
+            target_arch = "sparc",
+            target_arch = "sparc64"
+        )))]
         t(0x0137f, "stopped (not terminated) by signal: 19 (SIGSTOP)");
+
         t(0x0ffff, "continued (WIFCONTINUED)");
     }
 
diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs
index 6a9d8fab1d4..0477b3d9a70 100644
--- a/library/std/src/sys/pal/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs
@@ -1,3 +1,4 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
 use libc::{self, c_char, c_int, RTP_ID};
 
 use crate::io::{self, ErrorKind};
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 83034761f3d..0fa610eebb4 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -3,7 +3,7 @@ use crate::mem::{self, ManuallyDrop};
 use crate::num::NonZero;
 #[cfg(all(target_os = "linux", target_env = "gnu"))]
 use crate::sys::weak::dlsym;
-#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
+#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))]
 use crate::sys::weak::weak;
 use crate::sys::{os, stack_overflow};
 use crate::time::Duration;
@@ -212,17 +212,31 @@ impl Thread {
         }
     }
 
+    #[cfg(target_os = "vxworks")]
+    pub fn set_name(name: &CStr) {
+        // FIXME(libc): adding real STATUS, ERROR type eventually.
+        extern "C" {
+            fn taskNameSet(task_id: libc::TASK_ID, task_name: *mut libc::c_char) -> libc::c_int;
+        }
+
+        //  VX_TASK_NAME_LEN is 31 in VxWorks 7.
+        const VX_TASK_NAME_LEN: usize = 31;
+
+        let mut name = truncate_cstr::<{ VX_TASK_NAME_LEN }>(name);
+        let res = unsafe { taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) };
+        debug_assert_eq!(res, libc::OK);
+    }
+
     #[cfg(any(
         target_env = "newlib",
         target_os = "l4re",
         target_os = "emscripten",
         target_os = "redox",
-        target_os = "vxworks",
         target_os = "hurd",
         target_os = "aix",
     ))]
     pub fn set_name(_name: &CStr) {
-        // Newlib, Emscripten, and VxWorks have no way to set a thread name.
+        // Newlib and Emscripten have no way to set a thread name.
     }
 
     #[cfg(not(target_os = "espidf"))]
@@ -291,6 +305,7 @@ impl Drop for Thread {
     target_os = "nto",
     target_os = "solaris",
     target_os = "illumos",
+    target_os = "vxworks",
     target_vendor = "apple",
 ))]
 fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
@@ -455,8 +470,20 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
 
                 Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
             }
+        } else if #[cfg(target_os = "vxworks")] {
+            // Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF
+            // expectations than the actual cores availability.
+            extern "C" {
+                fn vxCpuEnabledGet() -> libc::cpuset_t;
+            }
+
+            // SAFETY: `vxCpuEnabledGet` always fetches a mask with at least one bit set
+            unsafe{
+                let set = vxCpuEnabledGet();
+                Ok(NonZero::new_unchecked(set.count_ones() as usize))
+            }
         } else {
-            // FIXME: implement on vxWorks, Redox, l4re
+            // FIXME: implement on Redox, l4re
             Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
         }
     }
diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs
index e27fdb72256..ce995f5ed5a 100644
--- a/library/std/src/sys/pal/windows/net.rs
+++ b/library/std/src/sys/pal/windows/net.rs
@@ -21,6 +21,7 @@ pub mod netc {
     //!
     //! Some Windows API types are not quite what's expected by our cross-platform
     //! net code. E.g. naming differences or different pointer types.
+
     use core::ffi::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void};
 
     use crate::sys::c::{self, ADDRESS_FAMILY, ADDRINFOA, SOCKADDR, SOCKET};
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index c285e1530a5..06eae5a07b0 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -564,7 +564,7 @@ impl Stdio {
             Ok(io) => unsafe {
                 let io = Handle::from_raw_handle(io);
                 let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
-                io.into_raw_handle();
+                let _ = io.into_raw_handle(); // Don't close the handle
                 ret
             },
             // If no stdio handle is available, then propagate the null value.
diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs
index dc63a2219c3..575f2250eb9 100644
--- a/library/std/src/sys/pal/windows/stdio.rs
+++ b/library/std/src/sys/pal/windows/stdio.rs
@@ -94,7 +94,7 @@ fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> i
         unsafe {
             let handle = Handle::from_raw_handle(handle);
             let ret = handle.write(data);
-            handle.into_raw_handle(); // Don't close the handle
+            let _ = handle.into_raw_handle(); // Don't close the handle
             return ret;
         }
     }
@@ -243,7 +243,7 @@ impl io::Read for Stdin {
             unsafe {
                 let handle = Handle::from_raw_handle(handle);
                 let ret = handle.read(buf);
-                handle.into_raw_handle(); // Don't close the handle
+                let _ = handle.into_raw_handle(); // Don't close the handle
                 return ret;
             }
         }
diff --git a/library/stdarch b/library/stdarch
-Subproject df3618d9f35165f4bc548114e511c49c29e1fd9
+Subproject 47b929ddc521a78b0f699ba8d5c274d28593448
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index 258a0347451..11316004412 100644
--- a/src/bootstrap/download-ci-llvm-stamp
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -1,4 +1,4 @@
 Change this file to make users of the `download-ci-llvm` configuration download
 a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
 
-Last change is for: https://github.com/rust-lang/rust/pull/126298
+Last change is for: https://github.com/rust-lang/rust/pull/125642
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 8b71300cf85..7f7faf077d0 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -31,10 +31,6 @@ pub struct Std {
 }
 
 impl Std {
-    pub fn new(target: TargetSelection) -> Self {
-        Self::new_with_build_kind(target, None)
-    }
-
     pub fn new_with_build_kind(target: TargetSelection, kind: Option<Kind>) -> Self {
         Self { target, crates: vec![], override_build_kind: kind }
     }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 268e89c7f60..c09180e542f 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -26,7 +26,8 @@ use crate::core::builder::{
 use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
 use crate::utils::exec::command;
 use crate::utils::helpers::{
-    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
+    self, exe, get_clang_cl_resource_dir, get_closest_merge_base_commit, is_debug_info, is_dylib,
+    symlink_dir, t, up_to_date,
 };
 use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS};
 
@@ -114,21 +115,43 @@ impl Step for Std {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        // When downloading stage1, the standard library has already been copied to the sysroot, so
-        // there's no need to rebuild it.
-        let builder = run.builder;
-        run.crate_or_deps("sysroot")
-            .path("library")
-            .lazy_default_condition(Box::new(|| !builder.download_rustc()))
+        run.crate_or_deps("sysroot").path("library")
     }
 
     fn make_run(run: RunConfig<'_>) {
         let crates = std_crates_for_run_make(&run);
+        let builder = run.builder;
+
+        // Force compilation of the standard library from source if the `library` is modified. This allows
+        // library team to compile the standard library without needing to compile the compiler with
+        // the `rust.download-rustc=true` option.
+        let force_recompile =
+            if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
+                let closest_merge_commit = get_closest_merge_base_commit(
+                    Some(&builder.src),
+                    &builder.config.git_config(),
+                    &builder.config.stage0_metadata.config.git_merge_commit_email,
+                    &[],
+                )
+                .unwrap();
+
+                // Check if `library` has changes (returns false otherwise)
+                !t!(helpers::git(Some(&builder.src))
+                    .args(["diff-index", "--quiet", &closest_merge_commit])
+                    .arg("--")
+                    .arg(builder.src.join("library"))
+                    .as_command_mut()
+                    .status())
+                .success()
+            } else {
+                false
+            };
+
         run.builder.ensure(Std {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
             crates,
-            force_recompile: false,
+            force_recompile,
             extra_rust_args: &[],
             is_for_mir_opt_tests: false,
         });
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 58f86aa996d..43306eab1b1 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -918,7 +918,6 @@ impl Step for Src {
         // translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs`
         let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
 
-        let src_files = ["Cargo.lock"];
         // This is the reduced set of paths which will become the rust-src component
         // (essentially libstd and all of its path dependencies).
         copy_src_dirs(
@@ -937,9 +936,6 @@ impl Step for Src {
             ],
             &dst_src,
         );
-        for file in src_files.iter() {
-            builder.copy_link(&builder.src.join(file), &dst_src.join(file));
-        }
 
         tarball.generate()
     }
@@ -1034,6 +1030,8 @@ impl Step for PlainSourceTarball {
                 .arg("--sync")
                 .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml"))
                 .arg("--sync")
+                .arg(builder.src.join("./library/Cargo.toml"))
+                .arg("--sync")
                 .arg(builder.src.join("./src/bootstrap/Cargo.toml"))
                 .arg("--sync")
                 .arg(builder.src.join("./src/tools/opt-dist/Cargo.toml"))
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 1541396bfdd..2cd5db706c2 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -599,6 +599,16 @@ impl Step for Std {
     fn run(self, builder: &Builder<'_>) {
         let stage = self.stage;
         let target = self.target;
+        let crates = if self.crates.is_empty() {
+            builder
+                .in_tree_crates("sysroot", Some(target))
+                .iter()
+                .map(|c| c.name.to_string())
+                .collect()
+        } else {
+            self.crates
+        };
+
         let out = match self.format {
             DocumentationFormat::Html => builder.doc_out(target),
             DocumentationFormat::Json => builder.json_doc_out(target),
@@ -627,7 +637,7 @@ impl Step for Std {
             extra_args.push("--disable-minification");
         }
 
-        doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates);
+        doc_std(builder, self.format, stage, target, &out, &extra_args, &crates);
 
         // Don't open if the format is json
         if let DocumentationFormat::Json = self.format {
@@ -639,7 +649,7 @@ impl Step for Std {
             let index = out.join("std").join("index.html");
             builder.open_in_browser(index);
         } else {
-            for requested_crate in &*self.crates {
+            for requested_crate in crates {
                 if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
                     let index = out.join(requested_crate).join("index.html");
                     builder.open_in_browser(index);
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 81e591be699..ffae245dfb5 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -368,9 +368,7 @@ impl Step for Llvm {
             cfg.define("LLVM_PROFDATA_FILE", path);
         }
 
-        // Disable zstd to avoid a dependency on libzstd.so.
-        cfg.define("LLVM_ENABLE_ZSTD", "OFF");
-
+        // Libraries for ELF section compression.
         if !target.is_windows() {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
         } else {
@@ -824,6 +822,14 @@ fn configure_llvm(builder: &Builder<'_>, target: TargetSelection, cfg: &mut cmak
         }
     }
 
+    // Libraries for ELF section compression.
+    if builder.config.llvm_libzstd {
+        cfg.define("LLVM_ENABLE_ZSTD", "FORCE_ON");
+        cfg.define("LLVM_USE_STATIC_ZSTD", "TRUE");
+    } else {
+        cfg.define("LLVM_ENABLE_ZSTD", "OFF");
+    }
+
     if let Some(ref linker) = builder.config.llvm_use_linker {
         cfg.define("LLVM_USE_LINKER", linker);
     }
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index fde1693646a..65d635c0bd6 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -212,11 +212,13 @@ impl Step for GenerateCopyright {
         let license_metadata = builder.ensure(CollectLicenseMetadata);
 
         // Temporary location, it will be moved to the proper one once it's accurate.
-        let dest = builder.out.join("COPYRIGHT.md");
+        let dest = builder.out.join("COPYRIGHT.html");
 
         let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
         cmd.env("LICENSE_METADATA", &license_metadata);
         cmd.env("DEST", &dest);
+        cmd.env("OUT_DIR", &builder.out);
+        cmd.env("CARGO", &builder.initial_cargo);
         cmd.run(builder);
 
         dest
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index c40aa718e7c..597d7733abe 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -520,6 +520,14 @@ impl Step for Miri {
         builder.ensure(compile::Std::new(target_compiler, host));
         let host_sysroot = builder.sysroot(target_compiler);
 
+        // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared
+        // properly when rustc changes. Similar to `Builder::cargo`, we skip this in dry runs to
+        // make sure the relevant compiler has been set up properly.
+        if !builder.config.dry_run() {
+            let ui_test_dep_dir = builder.stage_out(host_compiler, Mode::ToolStd).join("miri_ui");
+            builder.clear_if_dirty(&ui_test_dep_dir, &builder.rustc(host_compiler));
+        }
+
         // Run `cargo test`.
         // This is with the Miri crate, so it uses the host compiler.
         let mut cargo = tool::prepare_tool_cargo(
diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs
index 81770036d71..33768465225 100644
--- a/src/bootstrap/src/core/build_steps/vendor.rs
+++ b/src/bootstrap/src/core/build_steps/vendor.rs
@@ -47,6 +47,7 @@ impl Step for Vendor {
             "src/tools/rust-analyzer/Cargo.toml",
             "compiler/rustc_codegen_cranelift/Cargo.toml",
             "compiler/rustc_codegen_gcc/Cargo.toml",
+            "library/Cargo.toml",
             "src/bootstrap/Cargo.toml",
             "src/tools/rustbook/Cargo.toml",
         ] {
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 1343e257efe..915fcb449e8 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -218,6 +218,7 @@ pub struct Config {
     pub llvm_thin_lto: bool,
     pub llvm_release_debuginfo: bool,
     pub llvm_static_stdcpp: bool,
+    pub llvm_libzstd: bool,
     /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
     #[cfg(not(test))]
     llvm_link_shared: Cell<Option<bool>>,
@@ -512,6 +513,11 @@ impl TargetSelection {
     pub fn is_windows(&self) -> bool {
         self.contains("windows")
     }
+
+    /// Path to the file defining the custom target, if any.
+    pub fn filepath(&self) -> Option<&Path> {
+        self.file.as_ref().map(Path::new)
+    }
 }
 
 impl fmt::Display for TargetSelection {
@@ -873,6 +879,7 @@ define_config! {
         plugins: Option<bool> = "plugins",
         ccache: Option<StringOrBool> = "ccache",
         static_libstdcpp: Option<bool> = "static-libstdcpp",
+        libzstd: Option<bool> = "libzstd",
         ninja: Option<bool> = "ninja",
         targets: Option<String> = "targets",
         experimental_targets: Option<String> = "experimental-targets",
@@ -1148,6 +1155,7 @@ impl Config {
             llvm_optimize: true,
             ninja_in_file: true,
             llvm_static_stdcpp: false,
+            llvm_libzstd: false,
             backtrace: true,
             rust_optimize: RustOptimize::Bool(true),
             rust_optimize_tests: true,
@@ -1320,7 +1328,11 @@ impl Config {
         // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
         // but not if `config.toml` hasn't been created.
         let mut toml = if !using_default_path || toml_path.exists() {
-            config.config = Some(toml_path.clone());
+            config.config = Some(if cfg!(not(feature = "bootstrap-self-test")) {
+                toml_path.canonicalize().unwrap()
+            } else {
+                toml_path.clone()
+            });
             get_toml(&toml_path)
         } else {
             config.config = None;
@@ -1782,6 +1794,7 @@ impl Config {
                 plugins,
                 ccache,
                 static_libstdcpp,
+                libzstd,
                 ninja,
                 targets,
                 experimental_targets,
@@ -1816,6 +1829,7 @@ impl Config {
             set(&mut config.llvm_thin_lto, thin_lto);
             set(&mut config.llvm_release_debuginfo, release_debuginfo);
             set(&mut config.llvm_static_stdcpp, static_libstdcpp);
+            set(&mut config.llvm_libzstd, libzstd);
             if let Some(v) = link_shared {
                 config.llvm_link_shared.set(Some(v));
             }
@@ -1840,6 +1854,23 @@ impl Config {
             config.llvm_from_ci = config.parse_download_ci_llvm(download_ci_llvm, asserts);
 
             if config.llvm_from_ci {
+                let warn = |option: &str| {
+                    println!(
+                        "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build."
+                    );
+                    println!(
+                        "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false."
+                    );
+                };
+
+                if static_libstdcpp.is_some() {
+                    warn("static-libstdcpp");
+                }
+
+                if link_shared.is_some() {
+                    warn("link-shared");
+                }
+
                 // None of the LLVM options, except assertions, are supported
                 // when using downloaded LLVM. We could just ignore these but
                 // that's potentially confusing, so force them to not be
@@ -1849,9 +1880,7 @@ impl Config {
                 check_ci_llvm!(optimize_toml);
                 check_ci_llvm!(thin_lto);
                 check_ci_llvm!(release_debuginfo);
-                // CI-built LLVM can be either dynamic or static. We won't know until we download it.
-                check_ci_llvm!(link_shared);
-                check_ci_llvm!(static_libstdcpp);
+                check_ci_llvm!(libzstd);
                 check_ci_llvm!(targets);
                 check_ci_llvm!(experimental_targets);
                 check_ci_llvm!(clang_cl);
diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs
index 9b4c85e6d34..1016607fc83 100644
--- a/src/bootstrap/src/core/metadata.rs
+++ b/src/bootstrap/src/core/metadata.rs
@@ -86,6 +86,9 @@ fn workspace_members(build: &Build) -> Vec<Package> {
         packages
     };
 
-    // Collects `metadata.packages` from all workspaces.
-    collect_metadata("Cargo.toml")
+    // Collects `metadata.packages` from the root and library workspaces.
+    let mut packages = vec![];
+    packages.extend(collect_metadata("Cargo.toml"));
+    packages.extend(collect_metadata("library/Cargo.toml"));
+    packages
 }
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 45f4090ef22..c42d4c56c38 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -260,7 +260,9 @@ than building it.
 
             if !has_target {
                 // This might also be a custom target, so check the target file that could have been specified by the user.
-                if let Some(custom_target_path) = env::var_os("RUST_TARGET_PATH") {
+                if target.filepath().is_some_and(|p| p.exists()) {
+                    has_target = true;
+                } else if let Some(custom_target_path) = env::var_os("RUST_TARGET_PATH") {
                     let mut target_filename = OsString::from(&target_str);
                     // Target filename ends with `.json`.
                     target_filename.push(".json");
@@ -275,8 +277,12 @@ than building it.
 
             if !has_target {
                 panic!(
-                    "No such target exists in the target list,
-                specify a correct location of the JSON specification file for custom targets!"
+                    "No such target exists in the target list,\n\
+                     make sure to correctly specify the location \
+                     of the JSON specification file \
+                     for custom targets!\n\
+                     Use BOOTSTRAP_SKIP_TARGET_SANITY=1 to \
+                     bypass this check."
                 );
             }
         }
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 453fb39327d..2062d435bfc 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -986,7 +986,8 @@ impl Build {
     }
 
     /// Execute a command and return its output.
-    /// This method should be used for all command executions in bootstrap.
+    /// Note: Ideally, you should use one of the BootstrapCommand::run* functions to
+    /// execute commands. They internally call this method.
     #[track_caller]
     fn run(
         &self,
@@ -1057,20 +1058,28 @@ Executed at: {executed_at}"#,
                 CommandOutput::did_not_start(stdout, stderr)
             }
         };
+
+        let fail = |message: &str| {
+            if self.is_verbose() {
+                println!("{message}");
+            } else {
+                println!("Command has failed. Rerun with -v to see more details.");
+            }
+            exit!(1);
+        };
+
         if !output.is_success() {
             match command.failure_behavior {
                 BehaviorOnFailure::DelayFail => {
                     if self.fail_fast {
-                        println!("{message}");
-                        exit!(1);
+                        fail(&message);
                     }
 
                     let mut failures = self.delayed_failures.borrow_mut();
                     failures.push(message);
                 }
                 BehaviorOnFailure::Exit => {
-                    println!("{message}");
-                    exit!(1);
+                    fail(&message);
                 }
                 BehaviorOnFailure::Ignore => {
                     // If failures are allowed, either the error has been printed already
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index b8f70fdf6a8..84dac25188e 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -220,4 +220,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "For tarball sources, default value for `rust.channel` will be taken from `src/ci/channel` file.",
     },
+    ChangeInfo {
+        change_id: 125642,
+        severity: ChangeSeverity::Info,
+        summary: "New option `llvm.libzstd` to control whether llvm is built with zstd support.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 16959ce7e82..65e75f114bb 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -536,8 +536,7 @@ pub fn get_closest_merge_base_commit(
 
     let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into());
 
-    git.arg(Path::new("rev-list"));
-    git.args([&format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
+    git.args(["rev-list", &format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
 
     if !target_paths.is_empty() {
         git.arg("--").args(target_paths);
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index bfe2f084552..3f7f6214cf6 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -317,6 +317,12 @@ impl<'a> Tarball<'a> {
             channel::write_commit_hash_file(&self.overlay_dir, &info.sha);
             channel::write_commit_info_file(&self.overlay_dir, info);
         }
+
+        // Add config file if present.
+        if let Some(config) = &self.builder.config.config {
+            self.add_renamed_file(config, &self.overlay_dir, "builder-config");
+        }
+
         for file in self.overlay.legal_and_readme() {
             self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644);
         }
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 2621e9a6031..1b98d541693 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -24,7 +24,8 @@ RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no
   # Needed for apt-key to work:
   dirmngr \
   gpg-agent \
-  g++-9-arm-linux-gnueabi
+  g++-9-arm-linux-gnueabi \
+  g++-11-riscv64-linux-gnu
 
 RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486
 RUN add-apt-repository -y 'deb https://apt.dilos.org/dilos dilos2 main'
@@ -73,6 +74,10 @@ RUN env \
     CC=arm-linux-gnueabi-gcc-9 CFLAGS="-march=armv7-a" \
     CXX=arm-linux-gnueabi-g++-9 CXXFLAGS="-march=armv7-a" \
     bash musl.sh armv7 && \
+    env \
+    CC=riscv64-linux-gnu-gcc-11 \
+    CXX=riscv64-linux-gnu-g++-11 \
+    bash musl.sh riscv64gc && \
     rm -rf /build/*
 
 WORKDIR /tmp
@@ -125,6 +130,7 @@ ENV TARGETS=$TARGETS,x86_64-unknown-none
 ENV TARGETS=$TARGETS,aarch64-unknown-uefi
 ENV TARGETS=$TARGETS,i686-unknown-uefi
 ENV TARGETS=$TARGETS,x86_64-unknown-uefi
+ENV TARGETS=$TARGETS,riscv64gc-unknown-linux-musl
 
 # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
 # we need asm in the search path for gcc-9 (for gnux32) but not in the search path of the
@@ -132,7 +138,11 @@ ENV TARGETS=$TARGETS,x86_64-unknown-uefi
 # Luckily one of the folders is /usr/local/include so symlink /usr/include/x86_64-linux-gnu/asm there
 RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/local/include/asm
 
+# musl-gcc can't find libgcc_s.so.1 since it doesn't use the standard search paths.
+RUN ln -s /usr/riscv64-linux-gnu/lib/libgcc_s.so.1 /usr/lib/gcc-cross/riscv64-linux-gnu/11/
+
 ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-llvm-bitcode-linker --disable-docs \
-  --musl-root-armv7=/musl-armv7
+  --musl-root-armv7=/musl-armv7 \
+  --musl-root-riscv64gc=/musl-riscv64gc
 
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 4aa1a3ccc2a..61e9694f1e2 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -62,6 +62,10 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
 RUN ./build-clang.sh
 ENV CC=clang CXX=clang++
 
+# rustc's LLVM needs zstd.
+COPY scripts/zstd.sh /tmp/
+RUN ./zstd.sh
+
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
@@ -79,6 +83,7 @@ ENV RUST_CONFIGURE_ARGS \
       --set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \
       --set llvm.thin-lto=true \
       --set llvm.ninja=false \
+      --set llvm.libzstd=true \
       --set rust.jemalloc \
       --set rust.use-lld=true \
       --set rust.lto=thin \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
index 9025e9bb0a3..19683317126 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
@@ -17,6 +17,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config \
   xz-utils \
   mingw-w64 \
+  zlib1g-dev \
+  libzstd-dev \
   && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
index 00269e68422..a5458b8645d 100755
--- a/src/ci/docker/scripts/fuchsia-test-runner.py
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -571,6 +571,19 @@ class TestEnvironment:
         )
 
         # Start repository server
+        # Note that we must first enable the repository server daemon.
+        check_call_with_logging(
+            [
+                ffx_path,
+                "config",
+                "set",
+                "repository.server.enabled",
+                "true",
+            ],
+            env=ffx_env,
+            stdout_handler=self.subprocess_logger.debug,
+            stderr_handler=self.subprocess_logger.debug,
+        )
         check_call_with_logging(
             [
                 ffx_path,
diff --git a/src/ci/docker/scripts/zstd.sh b/src/ci/docker/scripts/zstd.sh
new file mode 100755
index 00000000000..a3d37ccc311
--- /dev/null
+++ b/src/ci/docker/scripts/zstd.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/zstd_build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  "$@" &> /tmp/zstd_build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  rm /tmp/zstd_build.log
+  set -x
+}
+
+ZSTD=1.5.6
+curl -L https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz | tar xzf -
+
+cd zstd-$ZSTD
+CFLAGS=-fPIC hide_output make -j$(nproc) VERBOSE=1
+hide_output make install
+
+cd ..
+rm -rf zstd-$ZSTD
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index d5141591b97..467fd6f43e4 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -66,6 +66,7 @@
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
     - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
     - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
+    - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 72ab8ab5ce9..fa23e3e414d 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -96,9 +96,7 @@ This modifier translates to `--whole-archive` for `ld`-like linkers,
 to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
 The modifier does nothing for linkers that don't support it.
 
-The default for this modifier is `-whole-archive`. \
-NOTE: The default may currently be different in some cases for backward compatibility,
-but it is not guaranteed. If you need whole archive semantics use `+whole-archive` explicitly.
+The default for this modifier is `-whole-archive`.
 
 ### Linking modifiers: `bundle`
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index f3b49a65aad..90e30f85bd6 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -98,6 +98,7 @@ target | notes
 `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
 `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
 [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
+[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
 `s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
 `x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
@@ -281,7 +282,7 @@ target | std | host | notes
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat
 `armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD
 [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float
-[`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ? |  | Armv7-A for VxWorks
+[`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ |  | Armv7-A for VxWorks
 [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3
 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
 [`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * |  | Bare Armv7-A, hardfloat
@@ -307,7 +308,7 @@ target | std | host | notes
 `i686-uwp-windows-gnu` | ✓ |  | [^x86_32-floats-return-ABI]
 `i686-uwp-windows-msvc` | ✓ |  | [^x86_32-floats-return-ABI]
 [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
-[`i686-wrs-vxworks`](platform-support/vxworks.md) | ? |  | [^x86_32-floats-return-ABI]
+[`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  | [^x86_32-floats-return-ABI]
 [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? |  | Motorola 680x0 Linux
 `mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
 `mips-unknown-linux-musl` | ✓ |  | MIPS Linux with musl 1.2.3
@@ -333,13 +334,13 @@ target | std | host | notes
 `powerpc-unknown-linux-musl` | ? |  | PowerPC Linux with musl 1.2.3
 [`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems
 [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * |  |
-[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ? |  |
-[`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ? |  |
+[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ |  |
+[`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
 `powerpc64le-unknown-freebsd` |   |   | PPC64LE FreeBSD
 `powerpc-unknown-freebsd` |   |   | PowerPC FreeBSD
 `powerpc64-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3
-`powerpc64-wrs-vxworks` | ? |  |
+[`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 `powerpc64le-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3, Little Endian
 [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64
 [`powerpc64-ibm-aix`](platform-support/aix.md) | ? |  | 64-bit AIX (7.2 and newer)
@@ -354,7 +355,6 @@ target | std | host | notes
 [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ |   | RISC-V Hermit
 `riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
 `riscv64gc-unknown-fuchsia` |   |   | RISC-V Fuchsia
-`riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.3)
 [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
 [`riscv64-linux-android`](platform-support/android.md) |   |   | RISC-V 64-bit Android
@@ -383,7 +383,7 @@ target | std | host | notes
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
 [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 64-bit Windows 7 support
-[`x86_64-wrs-vxworks`](platform-support/vxworks.md) | ? |  |
+[`x86_64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell)
 [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * |  | 64-bit Linux with no libc
 [`xtensa-esp32-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32
diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
new file mode 100644
index 00000000000..5b3dc683038
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
@@ -0,0 +1,47 @@
+# riscv64gc-unknown-linux-musl
+
+**Tier: 2**
+
+Target for RISC-V Linux programs using musl libc.
+
+## Target maintainers
+
+- [@Amanieu](https://github.com/Amanieu)
+- [@kraj](https://github.com/kraj)
+
+## Requirements
+
+Building the target itself requires a RISC-V compiler that is supported by `cc-rs`.
+
+## Building the target
+
+The target can be built by enabling it for a `rustc` build.
+
+```toml
+[build]
+target = ["riscv64gc-unknown-linux-musl"]
+```
+
+Make sure your C compiler is included in `$PATH`, then add it to the `config.toml`:
+
+```toml
+[target.riscv64gc-unknown-linux-musl]
+cc = "riscv64-linux-gnu-gcc"
+cxx = "riscv64-linux-gnu-g++"
+ar = "riscv64-linux-gnu-ar"
+linker = "riscv64-linux-gnu-gcc"
+```
+
+## Building Rust programs
+
+This target are distributed through `rustup`, and otherwise require no
+special configuration.
+
+## Cross-compilation
+
+This target can be cross-compiled from any host.
+
+## Testing
+
+This target can be tested as normal with `x.py` on a RISC-V host or via QEMU
+emulation.
diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md
index c0a818558e0..f1860346c8f 100644
--- a/src/doc/rustc/src/platform-support/vxworks.md
+++ b/src/doc/rustc/src/platform-support/vxworks.md
@@ -12,6 +12,7 @@ Target triplets available:
 - `i686-wrs-vxworks`
 - `armv7-wrs-vxworks-eabihf`
 - `powerpc-wrs-vxworks`
+- `powerpc64-wrs-vxworks`
 - `powerpc-wrs-vxworks-spe`
 
 ## Target maintainers
@@ -20,6 +21,12 @@ Target triplets available:
 
 ## Requirements
 
+### OS version
+
+The minimum supported version is VxWorks 7.
+
+## Building
+
 Rust for each target can be cross-compiled with its specific target vsb configuration. Std support is added but not yet fully tested.
 
 ## Building the target
@@ -36,6 +43,7 @@ target = [
     "i686-wrs-vxworks",
     "armv7-wrs-vxworks-eabihf",
     "powerpc-wrs-vxworks",
+    "powerpc64-wrs-vxworks",
     "powerpc-wrs-vxworks-spe",
 ]
 ```
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index dfd7414652f..b3fccbf6456 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -8,7 +8,7 @@ path = "lib.rs"
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
-rinja = { version = "0.2", default-features = false, features = ["config"] }
+rinja = { version = "0.3", default-features = false, features = ["config"] }
 base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index d92bc845664..f8953f0ebcf 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{sym, Symbol};
 use thin_vec::{thin_vec, ThinVec};
 use {rustc_ast as ast, rustc_hir as hir};
 
@@ -792,11 +792,7 @@ fn build_macro(
 fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
     for pred in &mut g.where_predicates {
         match *pred {
-            clean::WherePredicate::BoundPredicate {
-                ty: clean::Generic(ref s),
-                ref mut bounds,
-                ..
-            } if *s == kw::SelfUpper => {
+            clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } => {
                 bounds.retain(|bound| match bound {
                     clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
                         trait_.def_id() != trait_did
@@ -812,13 +808,13 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
         clean::WherePredicate::BoundPredicate {
             ty:
                 clean::QPath(box clean::QPathData {
-                    self_type: clean::Generic(ref s),
+                    self_type: clean::Generic(_),
                     trait_: Some(trait_),
                     ..
                 }),
             bounds,
             ..
-        } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
+        } => !bounds.is_empty() && trait_.def_id() != trait_did,
         _ => true,
     });
     g
@@ -832,9 +828,7 @@ fn separate_supertrait_bounds(
 ) -> (clean::Generics, Vec<clean::GenericBound>) {
     let mut ty_bounds = Vec::new();
     g.where_predicates.retain(|pred| match *pred {
-        clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. }
-            if *s == kw::SelfUpper =>
-        {
+        clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
             ty_bounds.extend(bounds.iter().cloned());
             false
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 324b633e8ea..cffadc7c10a 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1351,11 +1351,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                 let self_arg_ty =
                     tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
                 if self_arg_ty == self_ty {
-                    item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
+                    item.decl.inputs.values[0].type_ = SelfTy;
                 } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
                     if ty == self_ty {
                         match item.decl.inputs.values[0].type_ {
-                            BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
+                            BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
                             _ => unreachable!(),
                         }
                     }
@@ -1439,9 +1439,8 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                         if trait_.def_id() != assoc_item.container_id(tcx) {
                             return true;
                         }
-                        match *self_type {
-                            Generic(ref s) if *s == kw::SelfUpper => {}
-                            _ => return true,
+                        if *self_type != SelfTy {
+                            return true;
                         }
                         match &assoc.args {
                             GenericArgs::AngleBracketed { args, constraints } => {
@@ -2228,6 +2227,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Param(ref p) => {
             if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
                 ImplTrait(bounds)
+            } else if p.name == kw::SelfUpper {
+                SelfTy
             } else {
                 Generic(p.name)
             }
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 739f6eb8cc8..1d81ae3eb8b 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -145,7 +145,6 @@ pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generi
     // should be handled when cleaning associated types.
     generics.where_predicates.retain(|pred| {
         if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
-            && *param != rustc_span::symbol::kw::SelfUpper
             && bounds.iter().any(|b| b.is_sized_bound(cx))
         {
             sized_params.insert(*param);
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 3f8b9511d64..ff5c16f2b3e 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -34,10 +34,9 @@ use thin_vec::ThinVec;
 use {rustc_ast as ast, rustc_hir as hir};
 
 pub(crate) use self::ItemKind::*;
-pub(crate) use self::SelfTy::*;
 pub(crate) use self::Type::{
     Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
-    RawPointer, Slice, Tuple,
+    RawPointer, SelfTy, Slice, Tuple,
 };
 use crate::clean::cfg::Cfg;
 use crate::clean::clean_middle_path;
@@ -1384,8 +1383,8 @@ pub(crate) struct FnDecl {
 }
 
 impl FnDecl {
-    pub(crate) fn self_type(&self) -> Option<SelfTy> {
-        self.inputs.values.get(0).and_then(|v| v.to_self())
+    pub(crate) fn receiver_type(&self) -> Option<&Type> {
+        self.inputs.values.get(0).and_then(|v| v.to_receiver())
     }
 }
 
@@ -1403,27 +1402,9 @@ pub(crate) struct Argument {
     pub(crate) is_const: bool,
 }
 
-#[derive(Clone, PartialEq, Debug)]
-pub(crate) enum SelfTy {
-    SelfValue,
-    SelfBorrowed(Option<Lifetime>, Mutability),
-    SelfExplicit(Type),
-}
-
 impl Argument {
-    pub(crate) fn to_self(&self) -> Option<SelfTy> {
-        if self.name != kw::SelfLower {
-            return None;
-        }
-        if self.type_.is_self_type() {
-            return Some(SelfValue);
-        }
-        match self.type_ {
-            BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
-                Some(SelfBorrowed(lifetime.clone(), mutability))
-            }
-            _ => Some(SelfExplicit(self.type_.clone())),
-        }
+    pub(crate) fn to_receiver(&self) -> Option<&Type> {
+        if self.name == kw::SelfLower { Some(&self.type_) } else { None }
     }
 }
 
@@ -1477,6 +1458,8 @@ pub(crate) enum Type {
     DynTrait(Vec<PolyTrait>, Option<Lifetime>),
     /// A type parameter.
     Generic(Symbol),
+    /// The `Self` type.
+    SelfTy,
     /// A primitive (aka, builtin) type.
     Primitive(PrimitiveType),
     /// A function pointer: `extern "ABI" fn(...) -> ...`
@@ -1571,6 +1554,8 @@ impl Type {
             // If both sides are generic, this returns true.
             (_, Type::Generic(_)) => true,
             (Type::Generic(_), _) => false,
+            // `Self` only matches itself.
+            (Type::SelfTy, Type::SelfTy) => true,
             // Paths account for both the path itself and its generics.
             (Type::Path { path: a }, Type::Path { path: b }) => {
                 a.def_id() == b.def_id()
@@ -1642,7 +1627,7 @@ impl Type {
 
     pub(crate) fn is_self_type(&self) -> bool {
         match *self {
-            Generic(name) => name == kw::SelfUpper,
+            SelfTy => true,
             _ => false,
         }
     }
@@ -1677,13 +1662,16 @@ impl Type {
         }
     }
 
-    fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
+    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
+    ///
+    /// [clean]: crate::clean
+    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
         let t: PrimitiveType = match *self {
             Type::Path { ref path } => return Some(path.def_id()),
             DynTrait(ref bounds, _) => return bounds.get(0).map(|b| b.trait_.def_id()),
-            Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
+            Primitive(p) => return cache.primitive_locations.get(&p).cloned(),
             BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
-            BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
+            BorrowedRef { ref type_, .. } => return type_.def_id(cache),
             Tuple(ref tys) => {
                 if tys.is_empty() {
                     PrimitiveType::Unit
@@ -1696,17 +1684,10 @@ impl Type {
             Array(..) => PrimitiveType::Array,
             Type::Pat(..) => PrimitiveType::Pat,
             RawPointer(..) => PrimitiveType::RawPointer,
-            QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache),
-            Generic(_) | Infer | ImplTrait(_) => return None,
+            QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
+            Generic(_) | SelfTy | Infer | ImplTrait(_) => return None,
         };
-        cache.and_then(|c| Primitive(t).def_id(c))
-    }
-
-    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
-    ///
-    /// [clean]: crate::clean
-    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
-        self.inner_def_id(Some(cache))
+        Primitive(t).def_id(cache)
     }
 }
 
@@ -2465,6 +2446,10 @@ impl Impl {
             .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
             .unwrap_or_default()
     }
+
+    pub(crate) fn is_negative_trait_impl(&self) -> bool {
+        matches!(self.polarity, ty::ImplPolarity::Negative)
+    }
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 2dd3041ab4c..68266f3506a 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -468,7 +468,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
     match path.res {
         Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
         Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
-            Generic(kw::SelfUpper)
+            Type::SelfTy
         }
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
         _ => {
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index e4549796b3e..9c7a9f8467f 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -362,9 +362,10 @@ impl Options {
         }
 
         let color = config::parse_color(early_dcx, matches);
-        let config::JsonConfig { json_rendered, json_unused_externs, .. } =
+        let config::JsonConfig { json_rendered, json_unused_externs, json_color, .. } =
             config::parse_json(early_dcx, matches);
-        let error_format = config::parse_error_format(early_dcx, matches, color, json_rendered);
+        let error_format =
+            config::parse_error_format(early_dcx, matches, color, json_color, json_rendered);
         let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
 
         let codegen_options = CodegenOptions::build(early_dcx, matches);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 3e1271f198c..08a4a3f3fb2 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -138,8 +138,8 @@ pub(crate) fn new_dcx(
         false,
     );
     let emitter: Box<DynEmitter> = match error_format {
-        ErrorOutputType::HumanReadable(kind) => {
-            let (short, color_config) = kind.unzip();
+        ErrorOutputType::HumanReadable(kind, color_config) => {
+            let short = kind.short();
             Box::new(
                 HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
                     .sm(source_map.map(|sm| sm as _))
@@ -150,7 +150,7 @@ pub(crate) fn new_dcx(
                     .ui_testing(unstable_opts.ui_testing),
             )
         }
-        ErrorOutputType::Json { pretty, json_rendered } => {
+        ErrorOutputType::Json { pretty, json_rendered, color_config } => {
             let source_map = source_map.unwrap_or_else(|| {
                 Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty()))
             });
@@ -161,6 +161,7 @@ pub(crate) fn new_dcx(
                     fallback_bundle,
                     pretty,
                     json_rendered,
+                    color_config,
                 )
                 .ui_testing(unstable_opts.ui_testing)
                 .diagnostic_width(diagnostic_width)
@@ -195,6 +196,7 @@ pub(crate) fn create_config(
         lint_cap,
         scrape_examples_options,
         expanded_args,
+        remap_path_prefix,
         ..
     }: RustdocOptions,
     RenderOptions { document_private, .. }: &RenderOptions,
@@ -247,6 +249,7 @@ pub(crate) fn create_config(
         describe_lints,
         crate_name,
         test,
+        remap_path_prefix,
         ..Options::default()
     };
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 41eb142dd1e..08d6a5a52b2 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -422,8 +422,8 @@ fn run_test(
             path_for_rustdoc.to_str().expect("target path must be valid unicode")
         }
     });
-    if let ErrorOutputType::HumanReadable(kind) = rustdoc_options.error_format {
-        let (short, color_config) = kind.unzip();
+    if let ErrorOutputType::HumanReadable(kind, color_config) = rustdoc_options.error_format {
+        let short = kind.short();
 
         if short {
             compiler.arg("--error-format").arg("short");
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 5012cddf83a..947bae99305 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -260,153 +260,21 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         }
 
         // Index this method for searching later on.
-        if let Some(s) = item.name.or_else(|| {
-            if item.is_stripped() {
-                None
-            } else if let clean::ImportItem(ref i) = *item.kind
-                && let clean::ImportKind::Simple(s) = i.kind
-            {
-                Some(s)
-            } else {
-                None
-            }
-        }) {
-            let (parent, is_inherent_impl_item) = match *item.kind {
-                clean::StrippedItem(..) => ((None, None), false),
-                clean::AssocConstItem(..) | clean::AssocTypeItem(..)
-                    if self
-                        .cache
-                        .parent_stack
-                        .last()
-                        .is_some_and(|parent| parent.is_trait_impl()) =>
+        let search_name = if !item.is_stripped() {
+            item.name.or_else(|| {
+                if let clean::ImportItem(ref i) = *item.kind
+                    && let clean::ImportKind::Simple(s) = i.kind
                 {
-                    // skip associated items in trait impls
-                    ((None, None), false)
-                }
-                clean::TyMethodItem(..)
-                | clean::TyAssocConstItem(..)
-                | clean::TyAssocTypeItem(..)
-                | clean::StructFieldItem(..)
-                | clean::VariantItem(..) => (
-                    (
-                        Some(
-                            self.cache
-                                .parent_stack
-                                .last()
-                                .expect("parent_stack is empty")
-                                .item_id()
-                                .expect_def_id(),
-                        ),
-                        Some(&self.cache.stack[..self.cache.stack.len() - 1]),
-                    ),
-                    false,
-                ),
-                clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
-                    if self.cache.parent_stack.is_empty() {
-                        ((None, None), false)
-                    } else {
-                        let last = self.cache.parent_stack.last().expect("parent_stack is empty 2");
-                        let did = match &*last {
-                            ParentStackItem::Impl {
-                                // impl Trait for &T { fn method(self); }
-                                //
-                                // When generating a function index with the above shape, we want it
-                                // associated with `T`, not with the primitive reference type. It should
-                                // show up as `T::method`, rather than `reference::method`, in the search
-                                // results page.
-                                for_: clean::Type::BorrowedRef { type_, .. },
-                                ..
-                            } => type_.def_id(&self.cache),
-                            ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache),
-                            ParentStackItem::Type(item_id) => item_id.as_def_id(),
-                        };
-                        let path = did
-                            .and_then(|did| self.cache.paths.get(&did))
-                            // The current stack not necessarily has correlation
-                            // for where the type was defined. On the other
-                            // hand, `paths` always has the right
-                            // information if present.
-                            .map(|(fqp, _)| &fqp[..fqp.len() - 1]);
-                        ((did, path), true)
-                    }
-                }
-                _ => ((None, Some(&*self.cache.stack)), false),
-            };
-
-            match parent {
-                (parent, Some(path)) if is_inherent_impl_item || !self.cache.stripped_mod => {
-                    debug_assert!(!item.is_stripped());
-
-                    // A crate has a module at its root, containing all items,
-                    // which should not be indexed. The crate-item itself is
-                    // inserted later on when serializing the search-index.
-                    if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root())
-                        && let ty = item.type_()
-                        && (ty != ItemType::StructField
-                            || u16::from_str_radix(s.as_str(), 10).is_err())
-                    {
-                        let desc =
-                            short_markdown_summary(&item.doc_value(), &item.link_names(self.cache));
-                        // For searching purposes, a re-export is a duplicate if:
-                        //
-                        // - It's either an inline, or a true re-export
-                        // - It's got the same name
-                        // - Both of them have the same exact path
-                        let defid = (match &*item.kind {
-                            &clean::ItemKind::ImportItem(ref import) => import.source.did,
-                            _ => None,
-                        })
-                        .or_else(|| item.item_id.as_def_id());
-                        // In case this is a field from a tuple struct, we don't add it into
-                        // the search index because its name is something like "0", which is
-                        // not useful for rustdoc search.
-                        self.cache.search_index.push(IndexItem {
-                            ty,
-                            defid,
-                            name: s,
-                            path: join_with_double_colon(path),
-                            desc,
-                            parent,
-                            parent_idx: None,
-                            exact_path: None,
-                            impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) =
-                                self.cache.parent_stack.last()
-                            {
-                                item_id.as_def_id()
-                            } else {
-                                None
-                            },
-                            search_type: get_function_type_for_search(
-                                &item,
-                                self.tcx,
-                                clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
-                                parent,
-                                self.cache,
-                            ),
-                            aliases: item.attrs.get_doc_aliases(),
-                            deprecation: item.deprecation(self.tcx),
-                        });
-                    }
+                    Some(s)
+                } else {
+                    None
                 }
-                (Some(parent), None) if is_inherent_impl_item => {
-                    // We have a parent, but we don't know where they're
-                    // defined yet. Wait for later to index this item.
-                    let impl_generics = clean_impl_generics(self.cache.parent_stack.last());
-                    self.cache.orphan_impl_items.push(OrphanImplItem {
-                        parent,
-                        item: item.clone(),
-                        impl_generics,
-                        impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) =
-                            self.cache.parent_stack.last()
-                        {
-                            item_id.as_def_id()
-                        } else {
-                            None
-                        },
-                    });
-                }
-                _ => {}
-            }
+            })
+        } else {
+            None
+        };
+        if let Some(name) = search_name {
+            add_item_to_search_index(self.tcx, &mut self.cache, &item, name)
         }
 
         // Keep track of the fully qualified path for this item.
@@ -442,16 +310,16 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                     // `public_items` map, so we can skip inserting into the
                     // paths map if there was already an entry present and we're
                     // not a public item.
-                    if !self.cache.paths.contains_key(&item.item_id.expect_def_id())
+                    let item_def_id = item.item_id.expect_def_id();
+                    if !self.cache.paths.contains_key(&item_def_id)
                         || self
                             .cache
                             .effective_visibilities
-                            .is_directly_public(self.tcx, item.item_id.expect_def_id())
+                            .is_directly_public(self.tcx, item_def_id)
                     {
-                        self.cache.paths.insert(
-                            item.item_id.expect_def_id(),
-                            (self.cache.stack.clone(), item.type_()),
-                        );
+                        self.cache
+                            .paths
+                            .insert(item_def_id, (self.cache.stack.clone(), item.type_()));
                     }
                 }
             }
@@ -513,9 +381,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                         && adt.is_fundamental()
                     {
                         for ty in generics {
-                            if let Some(did) = ty.def_id(self.cache) {
-                                dids.insert(did);
-                            }
+                            dids.extend(ty.def_id(self.cache));
                         }
                     }
                 }
@@ -528,32 +394,26 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                         .primitive_type()
                         .and_then(|t| self.cache.primitive_locations.get(&t).cloned());
 
-                    if let Some(did) = did {
-                        dids.insert(did);
-                    }
+                    dids.extend(did);
                 }
             }
 
             if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
                 for bound in generics {
-                    if let Some(did) = bound.def_id(self.cache) {
-                        dids.insert(did);
-                    }
+                    dids.extend(bound.def_id(self.cache));
                 }
             }
             let impl_item = Impl { impl_item: item };
-            if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
+            let impl_did = impl_item.def_id();
+            let trait_did = impl_item.trait_did();
+            if trait_did.map_or(true, |d| self.cache.traits.contains_key(&d)) {
                 for did in dids {
-                    if self.impl_ids.entry(did).or_default().insert(impl_item.def_id()) {
-                        self.cache
-                            .impls
-                            .entry(did)
-                            .or_insert_with(Vec::new)
-                            .push(impl_item.clone());
+                    if self.impl_ids.entry(did).or_default().insert(impl_did) {
+                        self.cache.impls.entry(did).or_default().push(impl_item.clone());
                     }
                 }
             } else {
-                let trait_did = impl_item.trait_did().expect("no trait did");
+                let trait_did = trait_did.expect("no trait did");
                 self.cache.orphan_trait_impls.push((trait_did, dids, impl_item));
             }
             None
@@ -572,6 +432,152 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
     }
 }
 
+fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) {
+    // Item has a name, so it must also have a DefId (can't be an impl, let alone a blanket or auto impl).
+    let item_def_id = item.item_id.as_def_id().unwrap();
+    let (parent_did, parent_path) = match *item.kind {
+        clean::StrippedItem(..) => return,
+        clean::AssocConstItem(..) | clean::AssocTypeItem(..)
+            if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) =>
+        {
+            // skip associated items in trait impls
+            return;
+        }
+        clean::TyMethodItem(..)
+        | clean::TyAssocConstItem(..)
+        | clean::TyAssocTypeItem(..)
+        | clean::StructFieldItem(..)
+        | clean::VariantItem(..) => {
+            // Don't index if containing module is stripped (i.e., private),
+            // or if item is tuple struct/variant field (name is a number -> not useful for search).
+            if cache.stripped_mod
+                || item.type_() == ItemType::StructField
+                    && name.as_str().chars().all(|c| c.is_digit(10))
+            {
+                return;
+            }
+            let parent_did =
+                cache.parent_stack.last().expect("parent_stack is empty").item_id().expect_def_id();
+            let parent_path = &cache.stack[..cache.stack.len() - 1];
+            (Some(parent_did), parent_path)
+        }
+        clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
+            let last = cache.parent_stack.last().expect("parent_stack is empty 2");
+            let parent_did = match &*last {
+                // impl Trait for &T { fn method(self); }
+                //
+                // When generating a function index with the above shape, we want it
+                // associated with `T`, not with the primitive reference type. It should
+                // show up as `T::method`, rather than `reference::method`, in the search
+                // results page.
+                ParentStackItem::Impl { for_: clean::Type::BorrowedRef { type_, .. }, .. } => {
+                    type_.def_id(&cache)
+                }
+                ParentStackItem::Impl { for_, .. } => for_.def_id(&cache),
+                ParentStackItem::Type(item_id) => item_id.as_def_id(),
+            };
+            let Some(parent_did) = parent_did else { return };
+            // The current stack reflects the CacheBuilder's recursive
+            // walk over HIR. For associated items, this is the module
+            // where the `impl` block is defined. That's an implementation
+            // detail that we don't want to affect the search engine.
+            //
+            // In particular, you can arrange things like this:
+            //
+            //     #![crate_name="me"]
+            //     mod private_mod {
+            //         impl Clone for MyThing { fn clone(&self) -> MyThing { MyThing } }
+            //     }
+            //     pub struct MyThing;
+            //
+            // When that happens, we need to:
+            // - ignore the `cache.stripped_mod` flag, since the Clone impl is actually
+            //   part of the public API even though it's defined in a private module
+            // - present the method as `me::MyThing::clone`, its publicly-visible path
+            // - deal with the fact that the recursive walk hasn't actually reached `MyThing`
+            //   until it's already past `private_mod`, since that's first, and doesn't know
+            //   yet if `MyThing` will actually be public or not (it could be re-exported)
+            //
+            // We accomplish the last two points by recording children of "orphan impls"
+            // in a field of the cache whose elements are added to the search index later,
+            // after cache building is complete (see `handle_orphan_impl_child`).
+            match cache.paths.get(&parent_did) {
+                Some((fqp, _)) => (Some(parent_did), &fqp[..fqp.len() - 1]),
+                None => {
+                    handle_orphan_impl_child(cache, item, parent_did);
+                    return;
+                }
+            }
+        }
+        _ => {
+            // Don't index if item is crate root, which is inserted later on when serializing the index.
+            // Don't index if containing module is stripped (i.e., private),
+            if item_def_id.is_crate_root() || cache.stripped_mod {
+                return;
+            }
+            (None, &*cache.stack)
+        }
+    };
+
+    debug_assert!(!item.is_stripped());
+
+    let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
+    // For searching purposes, a re-export is a duplicate if:
+    //
+    // - It's either an inline, or a true re-export
+    // - It's got the same name
+    // - Both of them have the same exact path
+    let defid = match &*item.kind {
+        clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id),
+        _ => item_def_id,
+    };
+    let path = join_with_double_colon(parent_path);
+    let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
+        item_id.as_def_id()
+    } else {
+        None
+    };
+    let search_type = get_function_type_for_search(
+        &item,
+        tcx,
+        clean_impl_generics(cache.parent_stack.last()).as_ref(),
+        parent_did,
+        cache,
+    );
+    let aliases = item.attrs.get_doc_aliases();
+    let deprecation = item.deprecation(tcx);
+    let index_item = IndexItem {
+        ty: item.type_(),
+        defid: Some(defid),
+        name,
+        path,
+        desc,
+        parent: parent_did,
+        parent_idx: None,
+        exact_path: None,
+        impl_id,
+        search_type,
+        aliases,
+        deprecation,
+    };
+    cache.search_index.push(index_item);
+}
+
+/// We have a parent, but we don't know where they're
+/// defined yet. Wait for later to index this item.
+/// See [`Cache::orphan_impl_items`].
+fn handle_orphan_impl_child(cache: &mut Cache, item: &clean::Item, parent_did: DefId) {
+    let impl_generics = clean_impl_generics(cache.parent_stack.last());
+    let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
+        item_id.as_def_id()
+    } else {
+        None
+    };
+    let orphan_item =
+        OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id };
+    cache.orphan_impl_items.push(orphan_item);
+}
+
 pub(crate) struct OrphanImplItem {
     pub(crate) parent: DefId,
     pub(crate) impl_id: Option<DefId>,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index bb5ac303ffd..6357cfee141 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1006,6 +1006,7 @@ fn fmt_type<'cx>(
 
     match *t {
         clean::Generic(name) => f.write_str(name.as_str()),
+        clean::SelfTy => f.write_str("Self"),
         clean::Type::Path { ref path } => {
             // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
             let did = path.def_id();
@@ -1284,9 +1285,8 @@ impl clean::Impl {
             f.write_str(" ")?;
 
             if let Some(ref ty) = self.trait_ {
-                match self.polarity {
-                    ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {}
-                    ty::ImplPolarity::Negative => write!(f, "!")?,
+                if self.is_negative_trait_impl() {
+                    write!(f, "!")?;
                 }
                 ty.print(cx).fmt(f)?;
                 write!(f, " for ")?;
@@ -1452,29 +1452,22 @@ impl clean::FnDecl {
 
         let last_input_index = self.inputs.values.len().checked_sub(1);
         for (i, input) in self.inputs.values.iter().enumerate() {
-            if let Some(selfty) = input.to_self() {
+            if let Some(selfty) = input.to_receiver() {
                 match selfty {
-                    clean::SelfValue => {
+                    clean::SelfTy => {
                         write!(f, "self")?;
                     }
-                    clean::SelfBorrowed(Some(ref lt), mutability) => {
-                        write!(
-                            f,
-                            "{amp}{lifetime} {mutability}self",
-                            lifetime = lt.print(),
-                            mutability = mutability.print_with_space(),
-                        )?;
-                    }
-                    clean::SelfBorrowed(None, mutability) => {
-                        write!(
-                            f,
-                            "{amp}{mutability}self",
-                            mutability = mutability.print_with_space(),
-                        )?;
+                    clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => {
+                        write!(f, "{amp}")?;
+                        match lifetime {
+                            Some(lt) => write!(f, "{lt} ", lt = lt.print())?,
+                            None => {}
+                        }
+                        write!(f, "{mutability}self", mutability = mutability.print_with_space())?;
                     }
-                    clean::SelfExplicit(ref typ) => {
+                    _ => {
                         write!(f, "self: ")?;
-                        typ.print(cx).fmt(f)?;
+                        selfty.print(cx).fmt(f)?;
                     }
                 }
             } else {
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 97d97808b93..bb8d39aaf1d 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -924,6 +924,7 @@ pub(crate) struct TagIterator<'a, 'tcx> {
     data: &'a str,
     is_in_attribute_block: bool,
     extra: Option<&'a ExtraInfo<'tcx>>,
+    is_error: bool,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -950,13 +951,20 @@ struct Indices {
 
 impl<'a, 'tcx> TagIterator<'a, 'tcx> {
     pub(crate) fn new(data: &'a str, extra: Option<&'a ExtraInfo<'tcx>>) -> Self {
-        Self { inner: data.char_indices().peekable(), data, is_in_attribute_block: false, extra }
+        Self {
+            inner: data.char_indices().peekable(),
+            data,
+            is_in_attribute_block: false,
+            extra,
+            is_error: false,
+        }
     }
 
-    fn emit_error(&self, err: impl Into<DiagMessage>) {
+    fn emit_error(&mut self, err: impl Into<DiagMessage>) {
         if let Some(extra) = self.extra {
             extra.error_invalid_codeblock_attr(err);
         }
+        self.is_error = true;
     }
 
     fn skip_separators(&mut self) -> Option<usize> {
@@ -1154,6 +1162,9 @@ impl<'a, 'tcx> Iterator for TagIterator<'a, 'tcx> {
     type Item = LangStringToken<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
+        if self.is_error {
+            return None;
+        }
         let Some(start) = self.skip_separators() else {
             if self.is_in_attribute_block {
                 self.emit_error("unclosed attribute block (`{}`): missing `}` at the end");
@@ -1342,14 +1353,15 @@ impl LangString {
             }
         };
 
-        call(&mut TagIterator::new(string, extra));
+        let mut tag_iter = TagIterator::new(string, extra);
+        call(&mut tag_iter);
 
         // ignore-foo overrides ignore
         if !ignores.is_empty() {
             data.ignore = Ignore::Some(ignores);
         }
 
-        data.rust &= !seen_custom_tag && (!seen_other_tags || seen_rust_tags);
+        data.rust &= !seen_custom_tag && (!seen_other_tags || seen_rust_tags) && !tag_iter.is_error;
 
         data
     }
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 971120d4991..e490099a92e 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -61,7 +61,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: "{rust}".into(), rust: true, ..Default::default() });
+    t(LangString { original: "{rust}".into(), rust: false, ..Default::default() });
     t(LangString {
         original: "{.rust}".into(),
         rust: true,
@@ -233,7 +233,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: "{class=first=second}".into(), rust: true, ..Default::default() });
+    t(LangString { original: "{class=first=second}".into(), rust: false, ..Default::default() });
     // error
     t(LangString {
         original: "{class=first.second}".into(),
@@ -261,7 +261,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: r#"{class=f"irst"}"#.into(), rust: true, ..Default::default() });
+    t(LangString { original: r#"{class=f"irst"}"#.into(), rust: false, ..Default::default() });
 }
 
 #[test]
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 9617f0d9a1f..7ce637d3ab4 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -58,7 +58,7 @@ use serde::{Serialize, Serializer};
 
 pub(crate) use self::context::*;
 pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
-use crate::clean::{self, ItemId, RenderedLink, SelfTy};
+use crate::clean::{self, ItemId, RenderedLink};
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
@@ -1372,21 +1372,20 @@ fn render_deref_methods(
 
 fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
     let self_type_opt = match *item.kind {
-        clean::MethodItem(ref method, _) => method.decl.self_type(),
-        clean::TyMethodItem(ref method) => method.decl.self_type(),
+        clean::MethodItem(ref method, _) => method.decl.receiver_type(),
+        clean::TyMethodItem(ref method) => method.decl.receiver_type(),
         _ => None,
     };
 
     if let Some(self_ty) = self_type_opt {
-        let (by_mut_ref, by_box, by_value) = match self_ty {
-            SelfTy::SelfBorrowed(_, mutability)
-            | SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
+        let (by_mut_ref, by_box, by_value) = match *self_ty {
+            clean::Type::BorrowedRef { mutability, .. } => {
                 (mutability == Mutability::Mut, false, false)
             }
-            SelfTy::SelfExplicit(clean::Type::Path { path }) => {
+            clean::Type::Path { ref path } => {
                 (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
             }
-            SelfTy::SelfValue => (false, false, true),
+            clean::Type::SelfTy => (false, false, true),
             _ => (false, false, false),
         };
 
@@ -1781,20 +1780,23 @@ fn render_impl(
 
     let mut impl_items = Buffer::empty_from(w);
     let mut default_impl_items = Buffer::empty_from(w);
+    let impl_ = i.inner_impl();
 
-    for trait_item in &i.inner_impl().items {
-        doc_impl_item(
-            &mut default_impl_items,
-            &mut impl_items,
-            cx,
-            trait_item,
-            if trait_.is_some() { &i.impl_item } else { parent },
-            link,
-            render_mode,
-            false,
-            trait_,
-            rendering_params,
-        );
+    if !impl_.is_negative_trait_impl() {
+        for trait_item in &impl_.items {
+            doc_impl_item(
+                &mut default_impl_items,
+                &mut impl_items,
+                cx,
+                trait_item,
+                if trait_.is_some() { &i.impl_item } else { parent },
+                link,
+                render_mode,
+                false,
+                trait_,
+                rendering_params,
+            );
+        }
     }
 
     fn render_default_items(
@@ -1845,13 +1847,15 @@ fn render_impl(
     // We don't emit documentation for default items if they appear in the
     // Implementations on Foreign Types or Implementors sections.
     if rendering_params.show_default_items {
-        if let Some(t) = trait_ {
+        if let Some(t) = trait_
+            && !impl_.is_negative_trait_impl()
+        {
             render_default_items(
                 &mut default_impl_items,
                 &mut impl_items,
                 cx,
                 t,
-                i.inner_impl(),
+                impl_,
                 &i.impl_item,
                 render_mode,
                 rendering_params,
@@ -1883,7 +1887,7 @@ fn render_impl(
         }
 
         if let Some(ref dox) = i.impl_item.opt_doc_value() {
-            if trait_.is_none() && i.inner_impl().items.is_empty() {
+            if trait_.is_none() && impl_.items.is_empty() {
                 w.write_str(
                     "<div class=\"item-info\">\
                          <div class=\"stab empty-impl\">This impl block contains no items.</div>\
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index b3f4d82e054..8a2f31f7413 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -797,7 +797,11 @@ fn get_index_type_id(
             }
         }
         // Not supported yet
-        clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
+        clean::Type::Pat(..)
+        | clean::Generic(_)
+        | clean::SelfTy
+        | clean::ImplTrait(_)
+        | clean::Infer => None,
     }
 }
 
@@ -850,34 +854,70 @@ fn simplify_fn_type<'tcx, 'a>(
 
     // If this argument is a type parameter and not a trait bound or a type, we need to look
     // for its bounds.
-    if let Type::Generic(arg_s) = *arg {
-        // First we check if the bounds are in a `where` predicate...
-        let mut type_bounds = Vec::new();
-        for where_pred in generics.where_predicates.iter().filter(|g| match g {
-            WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s,
-            _ => false,
-        }) {
-            let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
-            for bound in bounds.iter() {
-                if let Some(path) = bound.get_trait_path() {
-                    let ty = Type::Path { path };
-                    simplify_fn_type(
-                        self_,
-                        generics,
-                        &ty,
-                        tcx,
-                        recurse + 1,
-                        &mut type_bounds,
-                        rgen,
-                        is_return,
-                        cache,
-                    );
+    match *arg {
+        Type::Generic(arg_s) => {
+            // First we check if the bounds are in a `where` predicate...
+            let mut type_bounds = Vec::new();
+            for where_pred in generics.where_predicates.iter().filter(|g| match g {
+                WherePredicate::BoundPredicate { ty, .. } => *ty == *arg,
+                _ => false,
+            }) {
+                let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
+                for bound in bounds.iter() {
+                    if let Some(path) = bound.get_trait_path() {
+                        let ty = Type::Path { path };
+                        simplify_fn_type(
+                            self_,
+                            generics,
+                            &ty,
+                            tcx,
+                            recurse + 1,
+                            &mut type_bounds,
+                            rgen,
+                            is_return,
+                            cache,
+                        );
+                    }
+                }
+            }
+            // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
+            if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
+                for bound in bound.get_bounds().unwrap_or(&[]) {
+                    if let Some(path) = bound.get_trait_path() {
+                        let ty = Type::Path { path };
+                        simplify_fn_type(
+                            self_,
+                            generics,
+                            &ty,
+                            tcx,
+                            recurse + 1,
+                            &mut type_bounds,
+                            rgen,
+                            is_return,
+                            cache,
+                        );
+                    }
                 }
             }
+            if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
+                res.push(RenderType {
+                    id: Some(RenderTypeId::Index(*idx)),
+                    generics: None,
+                    bindings: None,
+                });
+            } else {
+                let idx = -isize::try_from(rgen.len() + 1).unwrap();
+                rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
+                res.push(RenderType {
+                    id: Some(RenderTypeId::Index(idx)),
+                    generics: None,
+                    bindings: None,
+                });
+            }
         }
-        // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
-        if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
-            for bound in bound.get_bounds().unwrap_or(&[]) {
+        Type::ImplTrait(ref bounds) => {
+            let mut type_bounds = Vec::new();
+            for bound in bounds {
                 if let Some(path) = bound.get_trait_path() {
                     let ty = Type::Path { path };
                     simplify_fn_type(
@@ -893,84 +933,22 @@ fn simplify_fn_type<'tcx, 'a>(
                     );
                 }
             }
-        }
-        if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
-            res.push(RenderType {
-                id: Some(RenderTypeId::Index(*idx)),
-                generics: None,
-                bindings: None,
-            });
-        } else {
-            let idx = -isize::try_from(rgen.len() + 1).unwrap();
-            rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
-            res.push(RenderType {
-                id: Some(RenderTypeId::Index(idx)),
-                generics: None,
-                bindings: None,
-            });
-        }
-    } else if let Type::ImplTrait(ref bounds) = *arg {
-        let mut type_bounds = Vec::new();
-        for bound in bounds {
-            if let Some(path) = bound.get_trait_path() {
-                let ty = Type::Path { path };
-                simplify_fn_type(
-                    self_,
-                    generics,
-                    &ty,
-                    tcx,
-                    recurse + 1,
-                    &mut type_bounds,
-                    rgen,
-                    is_return,
-                    cache,
-                );
+            if is_return && !type_bounds.is_empty() {
+                // In return position, `impl Trait` is a unique thing.
+                res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
+            } else {
+                // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
+                let idx = -isize::try_from(rgen.len() + 1).unwrap();
+                rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
+                res.push(RenderType {
+                    id: Some(RenderTypeId::Index(idx)),
+                    generics: None,
+                    bindings: None,
+                });
             }
         }
-        if is_return && !type_bounds.is_empty() {
-            // In parameter position, `impl Trait` is a unique thing.
-            res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
-        } else {
-            // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
-            let idx = -isize::try_from(rgen.len() + 1).unwrap();
-            rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
-            res.push(RenderType {
-                id: Some(RenderTypeId::Index(idx)),
-                generics: None,
-                bindings: None,
-            });
-        }
-    } else if let Type::Slice(ref ty) = *arg {
-        let mut ty_generics = Vec::new();
-        simplify_fn_type(
-            self_,
-            generics,
-            &ty,
-            tcx,
-            recurse + 1,
-            &mut ty_generics,
-            rgen,
-            is_return,
-            cache,
-        );
-        res.push(get_index_type(arg, ty_generics, rgen));
-    } else if let Type::Array(ref ty, _) = *arg {
-        let mut ty_generics = Vec::new();
-        simplify_fn_type(
-            self_,
-            generics,
-            &ty,
-            tcx,
-            recurse + 1,
-            &mut ty_generics,
-            rgen,
-            is_return,
-            cache,
-        );
-        res.push(get_index_type(arg, ty_generics, rgen));
-    } else if let Type::Tuple(ref tys) = *arg {
-        let mut ty_generics = Vec::new();
-        for ty in tys {
+        Type::Slice(ref ty) => {
+            let mut ty_generics = Vec::new();
             simplify_fn_type(
                 self_,
                 generics,
@@ -982,15 +960,14 @@ fn simplify_fn_type<'tcx, 'a>(
                 is_return,
                 cache,
             );
+            res.push(get_index_type(arg, ty_generics, rgen));
         }
-        res.push(get_index_type(arg, ty_generics, rgen));
-    } else if let Type::BareFunction(ref bf) = *arg {
-        let mut ty_generics = Vec::new();
-        for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
+        Type::Array(ref ty, _) => {
+            let mut ty_generics = Vec::new();
             simplify_fn_type(
                 self_,
                 generics,
-                ty,
+                &ty,
                 tcx,
                 recurse + 1,
                 &mut ty_generics,
@@ -998,62 +975,11 @@ fn simplify_fn_type<'tcx, 'a>(
                 is_return,
                 cache,
             );
+            res.push(get_index_type(arg, ty_generics, rgen));
         }
-        // The search index, for simplicity's sake, represents fn pointers and closures
-        // the same way: as a tuple for the parameters, and an associated type for the
-        // return type.
-        let mut ty_output = Vec::new();
-        simplify_fn_type(
-            self_,
-            generics,
-            &bf.decl.output,
-            tcx,
-            recurse + 1,
-            &mut ty_output,
-            rgen,
-            is_return,
-            cache,
-        );
-        let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
-        res.push(RenderType {
-            id: get_index_type_id(&arg, rgen),
-            bindings: Some(ty_bindings),
-            generics: Some(ty_generics),
-        });
-    } else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg {
-        let mut ty_generics = Vec::new();
-        if mutability.is_mut() {
-            ty_generics.push(RenderType {
-                id: Some(RenderTypeId::Mut),
-                generics: None,
-                bindings: None,
-            });
-        }
-        simplify_fn_type(
-            self_,
-            generics,
-            &type_,
-            tcx,
-            recurse + 1,
-            &mut ty_generics,
-            rgen,
-            is_return,
-            cache,
-        );
-        res.push(get_index_type(arg, ty_generics, rgen));
-    } else {
-        // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
-        // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
-        //
-        // So in here, we can add it directly and look for its own type parameters (so for `Option`,
-        // we will look for them but not for `T`).
-        let mut ty_generics = Vec::new();
-        let mut ty_constraints = Vec::new();
-        if let Some(arg_generics) = arg.generic_args() {
-            for ty in arg_generics.into_iter().filter_map(|param| match param {
-                clean::GenericArg::Type(ty) => Some(ty),
-                _ => None,
-            }) {
+        Type::Tuple(ref tys) => {
+            let mut ty_generics = Vec::new();
+            for ty in tys {
                 simplify_fn_type(
                     self_,
                     generics,
@@ -1066,94 +992,181 @@ fn simplify_fn_type<'tcx, 'a>(
                     cache,
                 );
             }
-            for constraint in arg_generics.constraints() {
-                simplify_fn_constraint(
+            res.push(get_index_type(arg, ty_generics, rgen));
+        }
+        Type::BareFunction(ref bf) => {
+            let mut ty_generics = Vec::new();
+            for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
+                simplify_fn_type(
                     self_,
                     generics,
-                    &constraint,
+                    ty,
                     tcx,
                     recurse + 1,
-                    &mut ty_constraints,
+                    &mut ty_generics,
                     rgen,
                     is_return,
                     cache,
                 );
             }
+            // The search index, for simplicity's sake, represents fn pointers and closures
+            // the same way: as a tuple for the parameters, and an associated type for the
+            // return type.
+            let mut ty_output = Vec::new();
+            simplify_fn_type(
+                self_,
+                generics,
+                &bf.decl.output,
+                tcx,
+                recurse + 1,
+                &mut ty_output,
+                rgen,
+                is_return,
+                cache,
+            );
+            let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
+            res.push(RenderType {
+                id: get_index_type_id(&arg, rgen),
+                bindings: Some(ty_bindings),
+                generics: Some(ty_generics),
+            });
         }
-        // Every trait associated type on self gets assigned to a type parameter index
-        // this same one is used later for any appearances of these types
-        //
-        // for example, Iterator::next is:
-        //
-        //     trait Iterator {
-        //         fn next(&mut self) -> Option<Self::Item>
-        //     }
-        //
-        // Self is technically just Iterator, but we want to pretend it's more like this:
-        //
-        //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
-        if is_self
-            && let Type::Path { path } = arg
-            && let def_id = path.def_id()
-            && let Some(trait_) = cache.traits.get(&def_id)
-            && trait_.items.iter().any(|at| at.is_ty_associated_type())
-        {
-            for assoc_ty in &trait_.items {
-                if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
-                    && let Some(name) = assoc_ty.name
-                {
-                    let idx = -isize::try_from(rgen.len() + 1).unwrap();
-                    let (idx, stored_bounds) = rgen
-                        .entry(SimplifiedParam::AssociatedType(def_id, name))
-                        .or_insert_with(|| (idx, Vec::new()));
-                    let idx = *idx;
-                    if stored_bounds.is_empty() {
-                        // Can't just pass stored_bounds to simplify_fn_type,
-                        // because it also accepts rgen as a parameter.
-                        // Instead, have it fill in this local, then copy it into the map afterward.
-                        let mut type_bounds = Vec::new();
-                        for bound in bounds {
-                            if let Some(path) = bound.get_trait_path() {
-                                let ty = Type::Path { path };
-                                simplify_fn_type(
-                                    self_,
-                                    generics,
-                                    &ty,
-                                    tcx,
-                                    recurse + 1,
-                                    &mut type_bounds,
-                                    rgen,
-                                    is_return,
-                                    cache,
-                                );
-                            }
-                        }
-                        let stored_bounds = &mut rgen
-                            .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
-                            .unwrap()
-                            .1;
+        Type::BorrowedRef { lifetime: _, mutability, ref type_ } => {
+            let mut ty_generics = Vec::new();
+            if mutability.is_mut() {
+                ty_generics.push(RenderType {
+                    id: Some(RenderTypeId::Mut),
+                    generics: None,
+                    bindings: None,
+                });
+            }
+            simplify_fn_type(
+                self_,
+                generics,
+                &type_,
+                tcx,
+                recurse + 1,
+                &mut ty_generics,
+                rgen,
+                is_return,
+                cache,
+            );
+            res.push(get_index_type(arg, ty_generics, rgen));
+        }
+        _ => {
+            // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
+            // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
+            //
+            // So in here, we can add it directly and look for its own type parameters (so for `Option`,
+            // we will look for them but not for `T`).
+            let mut ty_generics = Vec::new();
+            let mut ty_constraints = Vec::new();
+            if let Some(arg_generics) = arg.generic_args() {
+                for ty in arg_generics.into_iter().filter_map(|param| match param {
+                    clean::GenericArg::Type(ty) => Some(ty),
+                    _ => None,
+                }) {
+                    simplify_fn_type(
+                        self_,
+                        generics,
+                        &ty,
+                        tcx,
+                        recurse + 1,
+                        &mut ty_generics,
+                        rgen,
+                        is_return,
+                        cache,
+                    );
+                }
+                for constraint in arg_generics.constraints() {
+                    simplify_fn_constraint(
+                        self_,
+                        generics,
+                        &constraint,
+                        tcx,
+                        recurse + 1,
+                        &mut ty_constraints,
+                        rgen,
+                        is_return,
+                        cache,
+                    );
+                }
+            }
+            // Every trait associated type on self gets assigned to a type parameter index
+            // this same one is used later for any appearances of these types
+            //
+            // for example, Iterator::next is:
+            //
+            //     trait Iterator {
+            //         fn next(&mut self) -> Option<Self::Item>
+            //     }
+            //
+            // Self is technically just Iterator, but we want to pretend it's more like this:
+            //
+            //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
+            if is_self
+                && let Type::Path { path } = arg
+                && let def_id = path.def_id()
+                && let Some(trait_) = cache.traits.get(&def_id)
+                && trait_.items.iter().any(|at| at.is_ty_associated_type())
+            {
+                for assoc_ty in &trait_.items {
+                    if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
+                        && let Some(name) = assoc_ty.name
+                    {
+                        let idx = -isize::try_from(rgen.len() + 1).unwrap();
+                        let (idx, stored_bounds) = rgen
+                            .entry(SimplifiedParam::AssociatedType(def_id, name))
+                            .or_insert_with(|| (idx, Vec::new()));
+                        let idx = *idx;
                         if stored_bounds.is_empty() {
-                            *stored_bounds = type_bounds;
+                            // Can't just pass stored_bounds to simplify_fn_type,
+                            // because it also accepts rgen as a parameter.
+                            // Instead, have it fill in this local, then copy it into the map afterward.
+                            let mut type_bounds = Vec::new();
+                            for bound in bounds {
+                                if let Some(path) = bound.get_trait_path() {
+                                    let ty = Type::Path { path };
+                                    simplify_fn_type(
+                                        self_,
+                                        generics,
+                                        &ty,
+                                        tcx,
+                                        recurse + 1,
+                                        &mut type_bounds,
+                                        rgen,
+                                        is_return,
+                                        cache,
+                                    );
+                                }
+                            }
+                            let stored_bounds = &mut rgen
+                                .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
+                                .unwrap()
+                                .1;
+                            if stored_bounds.is_empty() {
+                                *stored_bounds = type_bounds;
+                            }
                         }
+                        ty_constraints.push((
+                            RenderTypeId::AssociatedType(name),
+                            vec![RenderType {
+                                id: Some(RenderTypeId::Index(idx)),
+                                generics: None,
+                                bindings: None,
+                            }],
+                        ))
                     }
-                    ty_constraints.push((
-                        RenderTypeId::AssociatedType(name),
-                        vec![RenderType {
-                            id: Some(RenderTypeId::Index(idx)),
-                            generics: None,
-                            bindings: None,
-                        }],
-                    ))
                 }
             }
-        }
-        let id = get_index_type_id(&arg, rgen);
-        if id.is_some() || !ty_generics.is_empty() {
-            res.push(RenderType {
-                id,
-                bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
-                generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
-            });
+            let id = get_index_type_id(&arg, rgen);
+            if id.is_some() || !ty_generics.is_empty() {
+                res.push(RenderType {
+                    id,
+                    bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
+                    generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
+                });
+            }
         }
     }
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index f4e231327a8..02a6bb8f548 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -930,7 +930,7 @@ a.doc-anchor {
 	left: -17px;
 	/* We add this padding so that when the cursor moves from the heading's text to the anchor,
 	   the anchor doesn't disappear. */
-	padding-right: 5px;
+	padding-right: 10px;
 	/* And this padding is used to make the anchor larger and easier to click on. */
 	padding-left: 3px;
 }
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 2356ae109be..62fbde6f225 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -390,13 +390,18 @@ function preLoadCss(cssUrl) {
             if (splitAt !== -1) {
                 const implId = savedHash.slice(0, splitAt);
                 const assocId = savedHash.slice(splitAt + 1);
-                const implElem = document.getElementById(implId);
-                if (implElem && implElem.parentElement.tagName === "SUMMARY" &&
-                    implElem.parentElement.parentElement.tagName === "DETAILS") {
-                    onEachLazy(implElem.parentElement.parentElement.querySelectorAll(
+                const implElems = document.querySelectorAll(
+                    `details > summary > section[id^="${implId}"]`,
+                );
+                onEachLazy(implElems, implElem => {
+                    const numbered = /^(.+?)-([0-9]+)$/.exec(implElem.id);
+                    if (implElem.id !== implId && (!numbered || numbered[1] !== implId)) {
+                        return false;
+                    }
+                    return onEachLazy(implElem.parentElement.parentElement.querySelectorAll(
                         `[id^="${assocId}"]`),
                         item => {
-                            const numbered = /([^-]+)-([0-9]+)/.exec(item.id);
+                            const numbered = /^(.+?)-([0-9]+)$/.exec(item.id);
                             if (item.id === assocId || (numbered && numbered[1] === assocId)) {
                                 openParentDetails(item);
                                 item.scrollIntoView();
@@ -404,10 +409,11 @@ function preLoadCss(cssUrl) {
                                 setTimeout(() => {
                                     window.location.replace("#" + item.id);
                                 }, 0);
+                                return true;
                             }
                         },
                     );
-                }
+                });
             }
         }
     }
@@ -1114,8 +1120,7 @@ function preLoadCss(cssUrl) {
         wrapper.style.left = 0;
         wrapper.style.right = "auto";
         wrapper.style.visibility = "hidden";
-        const body = document.getElementsByTagName("body")[0];
-        body.appendChild(wrapper);
+        document.body.appendChild(wrapper);
         const wrapperPos = wrapper.getBoundingClientRect();
         // offset so that the arrow points at the center of the "(i)"
         const finalPos = pos.left + window.scrollX - wrapperPos.width + 24;
@@ -1234,8 +1239,7 @@ function preLoadCss(cssUrl) {
                 }
                 window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;
             }
-            const body = document.getElementsByTagName("body")[0];
-            body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
+            document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
             clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
             window.CURRENT_TOOLTIP_ELEMENT = null;
         }
@@ -1832,7 +1836,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         let elem = event.target;
         while (!hasClass(elem, "example-wrap")) {
             elem = elem.parentElement;
-            if (elem.tagName === "body" || hasClass(elem, "docblock")) {
+            if (elem === document.body || hasClass(elem, "docblock")) {
                 return null;
             }
         }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index b56244f2d3b..b97d710c007 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -578,7 +578,7 @@ impl FromWithTcx<clean::Type> for Type {
     fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
         use clean::Type::{
             Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
-            RawPointer, Slice, Tuple,
+            RawPointer, SelfTy, Slice, Tuple,
         };
 
         match ty {
@@ -588,6 +588,8 @@ impl FromWithTcx<clean::Type> for Type {
                 traits: bounds.into_tcx(tcx),
             }),
             Generic(s) => Type::Generic(s.to_string()),
+            // FIXME: add dedicated variant to json Type?
+            SelfTy => Type::Generic("Self".to_owned()),
             Primitive(p) => Type::Primitive(p.as_sym().to_string()),
             BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
             Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index dd516c4cbd7..ea191dc89cf 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -216,13 +216,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     fn after_krate(&mut self) -> Result<(), Error> {
         debug!("Done with crate");
 
-        debug!("Adding Primitive impls");
-        for primitive in Rc::clone(&self.cache).primitive_locations.values() {
-            self.get_impls(*primitive);
-        }
-
         let e = ExternalCrate { crate_num: LOCAL_CRATE };
-
         let index = (*self.index).clone().into_inner();
 
         debug!("Constructing Output");
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index d1e2b9978f7..f807c3362c4 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -95,7 +95,14 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
             }
 
             clean::ModuleItem(..) => {
-                if i.item_id.is_local() && i.visibility(self.tcx) != Some(Visibility::Public) {
+                if i.item_id.is_local()
+                    && !is_item_reachable(
+                        self.tcx,
+                        self.is_json_output,
+                        self.effective_visibilities,
+                        i.item_id,
+                    )
+                {
                     debug!("Stripper: stripping module {:?}", i.name);
                     let old = mem::replace(&mut self.update_retained, false);
                     let ret = strip_item(self.fold_item_recur(i));
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index a93ac6ccaf1..999134a4090 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -634,7 +634,7 @@ pub struct Discriminant {
     /// hexadecimal, and underscores), making it unsuitable to be machine
     /// interpreted.
     ///
-    /// In some cases, when the value is to complex, this may be `"{ _ }"`.
+    /// In some cases, when the value is too complex, this may be `"{ _ }"`.
     /// When this occurs is unstable, and may change without notice.
     pub expr: String,
     /// The numerical value of the discriminant. Stored as a string due to
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index ff475b9571b..2b263f848e8 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -141,6 +141,7 @@ static TARGETS: &[&str] = &[
     "riscv64gc-unknown-hermit",
     "riscv64gc-unknown-none-elf",
     "riscv64gc-unknown-linux-gnu",
+    "riscv64gc-unknown-linux-musl",
     "s390x-unknown-linux-gnu",
     "sparc64-unknown-linux-gnu",
     "sparcv9-sun-solaris",
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 257b72b8adfb1f2aa9916cefca67285c2166627
+Subproject 0d8d22f83b066503f6b2b755925197e959e58b4
diff --git a/src/tools/clippy/.cargo/config.toml b/src/tools/clippy/.cargo/config.toml
index 7afdd068a99..ce07290d1e1 100644
--- a/src/tools/clippy/.cargo/config.toml
+++ b/src/tools/clippy/.cargo/config.toml
@@ -13,6 +13,13 @@ target-dir = "target"
 
 [unstable]
 binary-dep-depinfo = true
+profile-rustflags = true
 
 [profile.dev]
 split-debuginfo = "unpacked"
+
+# Add back the containing directory of the packages we have to refer to using --manifest-path
+[profile.dev.package.clippy_dev]
+rustflags = ["--remap-path-prefix", "=clippy_dev"]
+[profile.dev.package.lintcheck]
+rustflags = ["--remap-path-prefix", "=lintcheck"]
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index 06bf3b6fdbf..0a0538490cc 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -25,6 +25,7 @@ env:
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
   CARGO_INCREMENTAL: 0
+  RUSTFLAGS: -D warnings
 
 concurrency:
   # For a given workflow, if we push to the same PR, cancel all previous builds on that PR.
@@ -47,25 +48,25 @@ jobs:
 
     # Run
     - name: Build
-      run: cargo build --tests --features deny-warnings,internal
+      run: cargo build --tests --features internal
 
     - name: Test
-      run: cargo test --features deny-warnings,internal
+      run: cargo test --features internal
 
     - name: Test clippy_lints
-      run: cargo test --features deny-warnings,internal
+      run: cargo test --features internal
       working-directory: clippy_lints
 
     - name: Test clippy_utils
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_utils
 
     - name: Test rustc_tools_util
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: rustc_tools_util
 
     - name: Test clippy_dev
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_dev
 
     - name: Test clippy-driver
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 1f4bec92918..10e18e84c89 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -11,6 +11,7 @@ env:
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
   CARGO_INCREMENTAL: 0
+  RUSTFLAGS: -D warnings
 
 concurrency:
   # For a given workflow, if we push to the same branch, cancel all previous builds on that branch.
@@ -85,34 +86,34 @@ jobs:
 
     # Run
     - name: Build
-      run: cargo build --tests --features deny-warnings,internal
+      run: cargo build --tests --features internal
 
     - name: Test
       if: matrix.host == 'x86_64-unknown-linux-gnu'
-      run: cargo test --features deny-warnings,internal
+      run: cargo test --features internal
 
     - name: Test
       if: matrix.host != 'x86_64-unknown-linux-gnu'
-      run: cargo test --features deny-warnings,internal -- --skip dogfood
+      run: cargo test --features internal -- --skip dogfood
 
     - name: Test clippy_lints
-      run: cargo test --features deny-warnings,internal
+      run: cargo test --features internal
       working-directory: clippy_lints
 
     - name: Test clippy_utils
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_utils
 
     - name: Test clippy_config
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_config
 
     - name: Test rustc_tools_util
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: rustc_tools_util
 
     - name: Test clippy_dev
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_dev
 
     - name: Test clippy-driver
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index 37f18a4c087..cf0a8bde202 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -16,6 +16,7 @@ on:
 env:
   RUST_BACKTRACE: 1
   CARGO_INCREMENTAL: 0
+  RUSTFLAGS: -D warnings
 
 jobs:
   clippy_dev:
@@ -28,7 +29,7 @@ jobs:
 
     # Run
     - name: Build
-      run: cargo build --features deny-warnings
+      run: cargo build
       working-directory: clippy_dev
 
     - name: Test update_lints
@@ -38,6 +39,8 @@ jobs:
       run: cargo dev fmt --check
 
     - name: Test cargo dev new lint
+      env:
+        RUSTFLAGS: -A unused-imports
       run: |
         cargo dev new_lint --name new_early_pass --pass early
         cargo dev new_lint --name new_late_pass --pass late
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
index 6a5139b6dc0..3cbda0b3824 100644
--- a/src/tools/clippy/.github/workflows/lintcheck.yml
+++ b/src/tools/clippy/.github/workflows/lintcheck.yml
@@ -58,7 +58,7 @@ jobs:
 
     - name: Run lintcheck
       if: steps.cache-json.outputs.cache-hit != 'true'
-      run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml
+      run: ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml
 
     - name: Upload base JSON
       uses: actions/upload-artifact@v4
@@ -86,7 +86,7 @@ jobs:
       run: cargo build --manifest-path=lintcheck/Cargo.toml
 
     - name: Run lintcheck
-      run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml
+      run: ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml
 
     - name: Upload head JSON
       uses: actions/upload-artifact@v4
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 60c03b03d9b..fddc2fd994e 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5830,6 +5830,7 @@ Released 2018-09-13
 [`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 [`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
 [`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
+[`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop
 [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
 [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
@@ -5998,6 +5999,7 @@ Released 2018-09-13
 [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
 [`unused_peekable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_peekable
+[`unused_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_result_ok
 [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding
 [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index bb4dc97e748..78409c7a09e 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -30,7 +30,7 @@ color-print = "0.3.4"
 anstream = "0.6.0"
 
 [dev-dependencies]
-ui_test = "0.24"
+ui_test = "0.25"
 regex = "1.5.5"
 toml = "0.7.3"
 walkdir = "2.3"
@@ -51,7 +51,6 @@ tokio = { version = "1", features = ["io-util"] }
 rustc_tools_util = "0.3.0"
 
 [features]
-deny-warnings = ["clippy_lints/deny-warnings"]
 integration = ["tempfile"]
 internal = ["clippy_lints/internal", "tempfile"]
 
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index fb717a2c166..e3d550b1466 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -364,7 +364,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
 
 
 ## `await-holding-invalid-types`
-
+The list of types which may not be held across an await point.
 
 **Default Value:** `[]`
 
@@ -668,6 +668,8 @@ crate. For example, `pub(crate)` items.
 ## `msrv`
 The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
 
+**Default Value:** `current version`
+
 ---
 **Affected lints:**
 * [`allow_attributes`](https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes)
@@ -862,6 +864,8 @@ The maximum number of lines a function or method can have
 The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
 reference. By default there is no limit
 
+**Default Value:** `target_pointer_width * 2`
+
 ---
 **Affected lints:**
 * [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index e1b2edc8a6f..d5b28e25323 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+itertools = "0.12"
 rustc-semver = "1.1"
 serde = { version = "1.0", features = ["derive"] }
 toml = "0.7.3"
@@ -13,9 +14,6 @@ toml = "0.7.3"
 [dev-dependencies]
 walkdir = "2.3"
 
-[features]
-deny-warnings = []
-
 [package.metadata.rust-analyzer]
 # This crate uses #[feature(rustc_private)]
 rustc_private = true
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 63140a36875..4c2a8255d6b 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -123,7 +123,8 @@ macro_rules! define_Conf {
         $(#[doc = $doc:literal])+
         $(#[conf_deprecated($dep:literal, $new_conf:ident)])?
         $(#[default_text = $default_text:expr])?
-        ($name:ident: $ty:ty = $default:expr),
+        $(#[lints($($for_lints:ident),* $(,)?)])?
+        $name:ident: $ty:ty = $default:expr,
     )*) => {
         /// Clippy lint configuration
         pub struct Conf {
@@ -201,29 +202,128 @@ macro_rules! define_Conf {
         }
 
         pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
-            let mut sorted = vec![
-                $(
-                    {
-                        let deprecation_reason = wrap_option!($($dep)?);
-
-                        ClippyConfiguration::new(
-                            stringify!($name),
-                            default_text!(defaults::$name() $(, $default_text)?),
-                            concat!($($doc, '\n',)*),
-                            deprecation_reason,
-                        )
-                    },
-                )+
-            ];
-            sorted.sort_by(|a, b| a.name.cmp(&b.name));
-            sorted
+            vec![$(
+                ClippyConfiguration {
+                    name: stringify!($name).replace('_', "-"),
+                    default: default_text!(defaults::$name() $(, $default_text)?),
+                    lints: &[$($(stringify!($for_lints)),*)?],
+                    doc: concat!($($doc, '\n',)*),
+                    deprecation_reason: wrap_option!($($dep)?)
+                },
+            )*]
         }
     };
 }
 
 define_Conf! {
-    /// Lint: ARITHMETIC_SIDE_EFFECTS.
+    /// Which crates to allow absolute paths from
+    #[lints(absolute_paths)]
+    absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default(),
+    /// The maximum number of segments a path can have before being linted, anything above this will
+    /// be linted.
+    #[lints(absolute_paths)]
+    absolute_paths_max_segments: u64 = 2,
+    /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
+    #[lints(undocumented_unsafe_blocks)]
+    accept_comment_above_attributes: bool = true,
+    /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
+    #[lints(undocumented_unsafe_blocks)]
+    accept_comment_above_statement: bool = true,
+    /// Don't lint when comparing the result of a modulo operation to zero.
+    #[lints(modulo_arithmetic)]
+    allow_comparison_to_zero: bool = true,
+    /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
+    #[lints(dbg_macro)]
+    allow_dbg_in_tests: bool = false,
+    /// Whether `expect` should be allowed in test functions or `#[cfg(test)]`
+    #[lints(expect_used)]
+    allow_expect_in_tests: bool = false,
+    /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
+    #[lints(uninlined_format_args)]
+    allow_mixed_uninlined_format_args: bool = true,
+    /// Whether to allow `r#""#` when `r""` can be used
+    #[lints(unnecessary_raw_string_hashes)]
+    allow_one_hash_in_raw_strings: bool = false,
+    /// Whether `panic` should be allowed in test functions or `#[cfg(test)]`
+    #[lints(panic)]
+    allow_panic_in_tests: bool = false,
+    /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
+    #[lints(print_stderr, print_stdout)]
+    allow_print_in_tests: bool = false,
+    /// Whether to allow module inception if it's not public.
+    #[lints(module_inception)]
+    allow_private_module_inception: bool = false,
+    /// List of trait paths to ignore when checking renamed function parameters.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allow-renamed-params-for = [ "std::convert::From" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr`
+    /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the
+    /// default configuration of Clippy. By default, any configuration will replace the default value.
+    #[lints(renamed_function_params)]
+    allow_renamed_params_for: Vec<String> =
+        DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect(),
+    /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
+    #[lints(unwrap_used)]
+    allow_unwrap_in_tests: bool = false,
+    /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]`
+    #[lints(useless_vec)]
+    allow_useless_vec_in_tests: bool = false,
+    /// Additional dotfiles (files or directories starting with a dot) to allow
+    #[lints(path_ends_with_ext)]
+    allowed_dotfiles: Vec<String> = Vec::default(),
+    /// A list of crate names to allow duplicates of
+    #[lints(multiple_crate_versions)]
+    allowed_duplicate_crates: FxHashSet<String> = FxHashSet::default(),
+    /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
+    /// the list to indicate, that the configured values should be appended to the default
+    /// configuration of Clippy. By default, any configuration will replace the default value.
+    #[lints(min_ident_chars)]
+    allowed_idents_below_min_chars: FxHashSet<String> =
+        DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect(),
+    /// List of prefixes to allow when determining whether an item's name ends with the module's name.
+    /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
+    /// then don't emit a warning.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allowed-prefixes = [ "to", "from" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
+    /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
+    ///   `TryInto` will also be included)
+    /// - Use `".."` as part of the list to indicate that the configured values should be appended to the
+    /// default configuration of Clippy. By default, any configuration will replace the default value
+    #[lints(module_name_repetitions)]
+    allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect(),
+    /// The list of unicode scripts allowed to be used in the scope.
+    #[lints(disallowed_script_idents)]
+    allowed_scripts: Vec<String> = vec!["Latin".to_string()],
+    /// List of path segments allowed to have wildcard imports.
     ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allowed-wildcard-imports = [ "utils", "common" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`.
+    /// 2. Paths with any segment that containing the word 'prelude'
+    /// are already allowed by default.
+    #[lints(wildcard_imports)]
+    allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default(),
     /// Suppress checking of the passed type names in all types of operations.
     ///
     /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
@@ -238,9 +338,8 @@ define_Conf! {
     ///
     /// A type, say `SomeType`, listed in this configuration has the same behavior of
     /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
-    (arithmetic_side_effects_allowed: Vec<String> = <_>::default()),
-    /// Lint: ARITHMETIC_SIDE_EFFECTS.
-    ///
+    #[lints(arithmetic_side_effects)]
+    arithmetic_side_effects_allowed: Vec<String> = <_>::default(),
     /// Suppress checking of the passed type pair names in binary operations like addition or
     /// multiplication.
     ///
@@ -255,9 +354,8 @@ define_Conf! {
     /// ```toml
     /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
     /// ```
-    (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()),
-    /// Lint: ARITHMETIC_SIDE_EFFECTS.
-    ///
+    #[lints(arithmetic_side_effects)]
+    arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default(),
     /// Suppress checking of the passed type names in unary operations like "negation" (`-`).
     ///
     /// #### Example
@@ -265,298 +363,78 @@ define_Conf! {
     /// ```toml
     /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
     /// ```
-    (arithmetic_side_effects_allowed_unary: Vec<String> = <_>::default()),
-    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT.
-    ///
+    #[lints(arithmetic_side_effects)]
+    arithmetic_side_effects_allowed_unary: Vec<String> = <_>::default(),
+    /// The maximum allowed size for arrays on the stack
+    #[lints(large_const_arrays, large_stack_arrays)]
+    array_size_threshold: u64 = 512_000,
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
-    (avoid_breaking_exported_api: bool = true),
-    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH.
-    ///
-    /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
-    #[default_text = ""]
-    (msrv: Msrv = Msrv::empty()),
+    #[lints(
+        box_collection,
+        enum_variant_names,
+        large_types_passed_by_value,
+        linkedlist,
+        needless_pass_by_ref_mut,
+        option_option,
+        rc_buffer,
+        rc_mutex,
+        redundant_allocation,
+        single_call_fn,
+        trivially_copy_pass_by_ref,
+        unnecessary_box_returns,
+        unnecessary_wraps,
+        unused_self,
+        upper_case_acronyms,
+        vec_box,
+        wrong_self_convention,
+    )]
+    avoid_breaking_exported_api: bool = true,
+    /// The list of types which may not be held across an await point.
+    #[lints(await_holding_invalid_type)]
+    await_holding_invalid_types: Vec<DisallowedPath> = Vec::new(),
     /// DEPRECATED LINT: BLACKLISTED_NAME.
     ///
     /// Use the Disallowed Names lint instead
     #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)]
-    (blacklisted_names: Vec<String> = Vec::new()),
-    /// Lint: COGNITIVE_COMPLEXITY.
-    ///
+    blacklisted_names: Vec<String> = Vec::new(),
+    /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
+    #[lints(cargo_common_metadata)]
+    cargo_ignore_publish: bool = false,
+    /// Whether to also run the listed lints on private items.
+    #[lints(missing_errors_doc, missing_panics_doc, missing_safety_doc, unnecessary_safety_doc)]
+    check_private_items: bool = false,
     /// The maximum cognitive complexity a function can have
-    (cognitive_complexity_threshold: u64 = 25),
-    /// Lint: EXCESSIVE_NESTING.
-    ///
-    /// The maximum amount of nesting a block can reside in
-    (excessive_nesting_threshold: u64 = 0),
+    #[lints(cognitive_complexity)]
+    cognitive_complexity_threshold: u64 = 25,
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
     ///
     /// Use the Cognitive Complexity lint instead.
     #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
-    (cyclomatic_complexity_threshold: u64 = 25),
-    /// Lint: DISALLOWED_NAMES.
-    ///
+    cyclomatic_complexity_threshold: u64 = 25,
+    /// The list of disallowed macros, written as fully qualified paths.
+    #[lints(disallowed_macros)]
+    disallowed_macros: Vec<DisallowedPath> = Vec::new(),
+    /// The list of disallowed methods, written as fully qualified paths.
+    #[lints(disallowed_methods)]
+    disallowed_methods: Vec<DisallowedPath> = Vec::new(),
     /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
     /// `".."` can be used as part of the list to indicate that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value.
-    (disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
-    /// Lint: SEMICOLON_INSIDE_BLOCK.
-    ///
-    /// Whether to lint only if it's multiline.
-    (semicolon_inside_block_ignore_singleline: bool = false),
-    /// Lint: SEMICOLON_OUTSIDE_BLOCK.
-    ///
-    /// Whether to lint only if it's singleline.
-    (semicolon_outside_block_ignore_multiline: bool = false),
-    /// Lint: DOC_MARKDOWN.
-    ///
+    #[lints(disallowed_names)]
+    disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(),
+    /// The list of disallowed types, written as fully qualified paths.
+    #[lints(disallowed_types)]
+    disallowed_types: Vec<DisallowedPath> = Vec::new(),
     /// The list of words this lint should not consider as identifiers needing ticks. The value
     /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value. For example:
     /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
     /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
-    (doc_valid_idents: FxHashSet<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()),
-    /// Lint: TOO_MANY_ARGUMENTS.
-    ///
-    /// The maximum number of argument a function or method can have
-    (too_many_arguments_threshold: u64 = 7),
-    /// Lint: TYPE_COMPLEXITY.
-    ///
-    /// The maximum complexity a type can have
-    (type_complexity_threshold: u64 = 250),
-    /// Lint: MANY_SINGLE_CHAR_NAMES.
-    ///
-    /// The maximum number of single char bindings a scope may have
-    (single_char_binding_names_threshold: u64 = 4),
-    /// Lint: BOXED_LOCAL, USELESS_VEC.
-    ///
-    /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
-    (too_large_for_stack: u64 = 200),
-    /// Lint: ENUM_VARIANT_NAMES.
-    ///
-    /// The minimum number of enum variants for the lints about variant names to trigger
-    (enum_variant_name_threshold: u64 = 3),
-    /// Lint: STRUCT_FIELD_NAMES.
-    ///
-    /// The minimum number of struct fields for the lints about field names to trigger
-    (struct_field_name_threshold: u64 = 3),
-    /// Lint: LARGE_ENUM_VARIANT.
-    ///
-    /// The maximum size of an enum's variant to avoid box suggestion
-    (enum_variant_size_threshold: u64 = 200),
-    /// Lint: VERBOSE_BIT_MASK.
-    ///
-    /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
-    (verbose_bit_mask_threshold: u64 = 1),
-    /// Lint: DECIMAL_LITERAL_REPRESENTATION.
-    ///
-    /// The lower bound for linting decimal literals
-    (literal_representation_threshold: u64 = 16384),
-    /// Lint: TRIVIALLY_COPY_PASS_BY_REF.
-    ///
-    /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
-    /// reference. By default there is no limit
-    #[default_text = ""]
-    (trivial_copy_size_limit: Option<u64> = None),
-    /// Lint: LARGE_TYPES_PASSED_BY_VALUE.
-    ///
-    /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
-    (pass_by_value_size_limit: u64 = 256),
-    /// Lint: TOO_MANY_LINES.
-    ///
-    /// The maximum number of lines a function or method can have
-    (too_many_lines_threshold: u64 = 100),
-    /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
-    ///
-    /// The maximum allowed size for arrays on the stack
-    (array_size_threshold: u64 = 512_000),
-    /// Lint: LARGE_STACK_FRAMES.
-    ///
-    /// The maximum allowed stack size for functions in bytes
-    (stack_size_threshold: u64 = 512_000),
-    /// Lint: VEC_BOX.
-    ///
-    /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
-    (vec_box_size_threshold: u64 = 4096),
-    /// Lint: TYPE_REPETITION_IN_BOUNDS.
-    ///
-    /// The maximum number of bounds a trait can have to be linted
-    (max_trait_bounds: u64 = 3),
-    /// Lint: STRUCT_EXCESSIVE_BOOLS.
-    ///
-    /// The maximum number of bool fields a struct can have
-    (max_struct_bools: u64 = 3),
-    /// Lint: FN_PARAMS_EXCESSIVE_BOOLS.
-    ///
-    /// The maximum number of bool parameters a function can have
-    (max_fn_params_bools: u64 = 3),
-    /// Lint: WILDCARD_IMPORTS.
-    ///
-    /// Whether to allow certain wildcard imports (prelude, super in tests).
-    (warn_on_all_wildcard_imports: bool = false),
-    /// Lint: DISALLOWED_MACROS.
-    ///
-    /// The list of disallowed macros, written as fully qualified paths.
-    (disallowed_macros: Vec<DisallowedPath> = Vec::new()),
-    /// Lint: DISALLOWED_METHODS.
-    ///
-    /// The list of disallowed methods, written as fully qualified paths.
-    (disallowed_methods: Vec<DisallowedPath> = Vec::new()),
-    /// Lint: DISALLOWED_TYPES.
-    ///
-    /// The list of disallowed types, written as fully qualified paths.
-    (disallowed_types: Vec<DisallowedPath> = Vec::new()),
-    /// Lint: UNREADABLE_LITERAL.
-    ///
-    /// Should the fraction of a decimal be linted to include separators.
-    (unreadable_literal_lint_fractions: bool = true),
-    /// Lint: UPPER_CASE_ACRONYMS.
-    ///
-    /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
-    (upper_case_acronyms_aggressive: bool = false),
-    /// Lint: MANUAL_LET_ELSE.
-    ///
-    /// Whether the matches should be considered by the lint, and whether there should
-    /// be filtering for common types.
-    (matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes),
-    /// Lint: CARGO_COMMON_METADATA.
-    ///
-    /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
-    (cargo_ignore_publish: bool = false),
-    /// Lint: NONSTANDARD_MACRO_BRACES.
-    ///
-    /// Enforce the named macros always use the braces specified.
-    ///
-    /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
-    /// could be used with a full path two `MacroMatcher`s have to be added one with the full path
-    /// `crate_name::macro_name` and one with just the macro name.
-    (standard_macro_braces: Vec<MacroMatcher> = Vec::new()),
-    /// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
-    ///
-    /// The list of imports to always rename, a fully qualified path followed by the rename.
-    (enforced_import_renames: Vec<Rename> = Vec::new()),
-    /// Lint: DISALLOWED_SCRIPT_IDENTS.
-    ///
-    /// The list of unicode scripts allowed to be used in the scope.
-    (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
-    /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
-    ///
+    #[lints(doc_markdown)]
+    doc_valid_idents: FxHashSet<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(),
     /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
-    (enable_raw_pointer_heuristic_for_send: bool = true),
-    /// Lint: INDEX_REFUTABLE_SLICE.
-    ///
-    /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
-    /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed.
-    /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
-    (max_suggested_slice_pattern_length: u64 = 3),
-    /// Lint: AWAIT_HOLDING_INVALID_TYPE.
-    (await_holding_invalid_types: Vec<DisallowedPath> = Vec::new()),
-    /// Lint: LARGE_INCLUDE_FILE.
-    ///
-    /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
-    (max_include_file_size: u64 = 1_000_000),
-    /// Lint: EXPECT_USED.
-    ///
-    /// Whether `expect` should be allowed in test functions or `#[cfg(test)]`
-    (allow_expect_in_tests: bool = false),
-    /// Lint: UNWRAP_USED.
-    ///
-    /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
-    (allow_unwrap_in_tests: bool = false),
-    /// Lint: PANIC.
-    ///
-    /// Whether `panic` should be allowed in test functions or `#[cfg(test)]`
-    (allow_panic_in_tests: bool = false),
-    /// Lint: DBG_MACRO.
-    ///
-    /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
-    (allow_dbg_in_tests: bool = false),
-    /// Lint: PRINT_STDOUT, PRINT_STDERR.
-    ///
-    /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
-    (allow_print_in_tests: bool = false),
-    /// Lint: USELESS_VEC.
-    ///
-    /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]`
-    (allow_useless_vec_in_tests: bool = false),
-    /// Lint: RESULT_LARGE_ERR.
-    ///
-    /// The maximum size of the `Err`-variant in a `Result` returned from a function
-    (large_error_threshold: u64 = 128),
-    /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST.
-    ///
-    /// A list of paths to types that should be treated as if they do not contain interior mutability
-    (ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()])),
-    /// Lint: UNINLINED_FORMAT_ARGS.
-    ///
-    /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
-    (allow_mixed_uninlined_format_args: bool = true),
-    /// Lint: INDEXING_SLICING.
-    ///
-    /// Whether to suppress a restriction lint in constant code. In same
-    /// cases the restructured operation might not be unavoidable, as the
-    /// suggested counterparts are unavailable in constant code. This
-    /// configuration will cause restriction lints to trigger even
-    /// if no suggestion can be made.
-    (suppress_restriction_lint_in_const: bool = false),
-    /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS.
-    ///
-    /// Whether to **only** check for missing documentation in items visible within the current
-    /// crate. For example, `pub(crate)` items.
-    (missing_docs_in_crate_items: bool = false),
-    /// Lint: LARGE_FUTURES.
-    ///
-    /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint
-    (future_size_threshold: u64 = 16 * 1024),
-    /// Lint: UNNECESSARY_BOX_RETURNS.
-    ///
-    /// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
-    (unnecessary_box_size: u64 = 128),
-    /// Lint: MODULE_INCEPTION.
-    ///
-    /// Whether to allow module inception if it's not public.
-    (allow_private_module_inception: bool = false),
-    /// Lint: MIN_IDENT_CHARS.
-    ///
-    /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
-    /// the list to indicate, that the configured values should be appended to the default
-    /// configuration of Clippy. By default, any configuration will replace the default value.
-    (allowed_idents_below_min_chars: FxHashSet<String> =
-        DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()),
-    /// Lint: MIN_IDENT_CHARS.
-    ///
-    /// Minimum chars an ident can have, anything below or equal to this will be linted.
-    (min_ident_chars_threshold: u64 = 1),
-    /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
-    ///
-    /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
-    (accept_comment_above_statement: bool = true),
-    /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
-    ///
-    /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
-    (accept_comment_above_attributes: bool = true),
-    /// Lint: UNNECESSARY_RAW_STRING_HASHES.
-    ///
-    /// Whether to allow `r#""#` when `r""` can be used
-    (allow_one_hash_in_raw_strings: bool = false),
-    /// Lint: ABSOLUTE_PATHS.
-    ///
-    /// The maximum number of segments a path can have before being linted, anything above this will
-    /// be linted.
-    (absolute_paths_max_segments: u64 = 2),
-    /// Lint: ABSOLUTE_PATHS.
-    ///
-    /// Which crates to allow absolute paths from
-    (absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default()),
-    /// Lint: PATH_ENDS_WITH_EXT.
-    ///
-    /// Additional dotfiles (files or directories starting with a dot) to allow
-    (allowed_dotfiles: Vec<String> = Vec::default()),
-    /// Lint: MULTIPLE_CRATE_VERSIONS.
-    ///
-    /// A list of crate names to allow duplicates of
-    (allowed_duplicate_crates: FxHashSet<String> = FxHashSet::default()),
-    /// Lint: EXPLICIT_ITER_LOOP.
-    ///
+    #[lints(non_send_fields_in_send_ty)]
+    enable_raw_pointer_heuristic_for_send: bool = true,
     /// Whether to recommend using implicit into iter for reborrowed values.
     ///
     /// #### Example
@@ -574,77 +452,195 @@ define_Conf! {
     /// for _ in &*rmvec {}
     /// for _ in &mut *rmvec {}
     /// ```
-    (enforce_iter_loop_reborrow: bool = false),
-    /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC.
-    ///
-    /// Whether to also run the listed lints on private items.
-    (check_private_items: bool = false),
-    /// Lint: PUB_UNDERSCORE_FIELDS.
-    ///
+    #[lints(explicit_iter_loop)]
+    enforce_iter_loop_reborrow: bool = false,
+    /// The list of imports to always rename, a fully qualified path followed by the rename.
+    #[lints(missing_enforced_import_renames)]
+    enforced_import_renames: Vec<Rename> = Vec::new(),
+    /// The minimum number of enum variants for the lints about variant names to trigger
+    #[lints(enum_variant_names)]
+    enum_variant_name_threshold: u64 = 3,
+    /// The maximum size of an enum's variant to avoid box suggestion
+    #[lints(large_enum_variant)]
+    enum_variant_size_threshold: u64 = 200,
+    /// The maximum amount of nesting a block can reside in
+    #[lints(excessive_nesting)]
+    excessive_nesting_threshold: u64 = 0,
+    /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint
+    #[lints(large_futures)]
+    future_size_threshold: u64 = 16 * 1024,
+    /// A list of paths to types that should be treated as if they do not contain interior mutability
+    #[lints(borrow_interior_mutable_const, declare_interior_mutable_const, ifs_same_cond, mutable_key_type)]
+    ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()]),
+    /// The maximum size of the `Err`-variant in a `Result` returned from a function
+    #[lints(result_large_err)]
+    large_error_threshold: u64 = 128,
+    /// The lower bound for linting decimal literals
+    #[lints(decimal_literal_representation)]
+    literal_representation_threshold: u64 = 16384,
+    /// Whether the matches should be considered by the lint, and whether there should
+    /// be filtering for common types.
+    #[lints(manual_let_else)]
+    matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes,
+    /// The maximum number of bool parameters a function can have
+    #[lints(fn_params_excessive_bools)]
+    max_fn_params_bools: u64 = 3,
+    /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
+    #[lints(large_include_file)]
+    max_include_file_size: u64 = 1_000_000,
+    /// The maximum number of bool fields a struct can have
+    #[lints(struct_excessive_bools)]
+    max_struct_bools: u64 = 3,
+    /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
+    /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed.
+    /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
+    #[lints(index_refutable_slice)]
+    max_suggested_slice_pattern_length: u64 = 3,
+    /// The maximum number of bounds a trait can have to be linted
+    #[lints(type_repetition_in_bounds)]
+    max_trait_bounds: u64 = 3,
+    /// Minimum chars an ident can have, anything below or equal to this will be linted.
+    #[lints(min_ident_chars)]
+    min_ident_chars_threshold: u64 = 1,
+    /// Whether to **only** check for missing documentation in items visible within the current
+    /// crate. For example, `pub(crate)` items.
+    #[lints(missing_docs_in_private_items)]
+    missing_docs_in_crate_items: bool = false,
+    /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
+    #[default_text = "current version"]
+    #[lints(
+        allow_attributes,
+        allow_attributes_without_reason,
+        almost_complete_range,
+        approx_constant,
+        assigning_clones,
+        borrow_as_ptr,
+        cast_abs_to_unsigned,
+        checked_conversions,
+        cloned_instead_of_copied,
+        collapsible_match,
+        collapsible_str_replace,
+        deprecated_cfg_attr,
+        derivable_impls,
+        err_expect,
+        filter_map_next,
+        from_over_into,
+        if_then_some_else_none,
+        index_refutable_slice,
+        iter_kv_map,
+        legacy_numeric_constants,
+        manual_bits,
+        manual_c_str_literals,
+        manual_clamp,
+        manual_hash_one,
+        manual_is_ascii_check,
+        manual_let_else,
+        manual_non_exhaustive,
+        manual_pattern_char_comparison,
+        manual_range_contains,
+        manual_rem_euclid,
+        manual_retain,
+        manual_split_once,
+        manual_str_repeat,
+        manual_strip,
+        manual_try_fold,
+        map_clone,
+        map_unwrap_or,
+        match_like_matches_macro,
+        mem_replace_with_default,
+        missing_const_for_fn,
+        needless_borrow,
+        option_as_ref_deref,
+        option_map_unwrap_or,
+        ptr_as_ptr,
+        redundant_field_names,
+        redundant_static_lifetimes,
+        seek_from_current,
+        seek_rewind,
+        transmute_ptr_to_ref,
+        tuple_array_conversions,
+        type_repetition_in_bounds,
+        unchecked_duration_subtraction,
+        uninlined_format_args,
+        unnecessary_lazy_evaluations,
+        unnested_or_patterns,
+        use_self,
+    )]
+    msrv: Msrv = Msrv::empty(),
+    /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
+    #[lints(large_types_passed_by_value)]
+    pass_by_value_size_limit: u64 = 256,
     /// Lint "public" fields in a struct that are prefixed with an underscore based on their
     /// exported visibility, or whether they are marked as "pub".
-    (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported),
-    /// Lint: MODULO_ARITHMETIC.
-    ///
-    /// Don't lint when comparing the result of a modulo operation to zero.
-    (allow_comparison_to_zero: bool = true),
-    /// Lint: WILDCARD_IMPORTS.
-    ///
-    /// List of path segments allowed to have wildcard imports.
-    ///
-    /// #### Example
-    ///
-    /// ```toml
-    /// allowed-wildcard-imports = [ "utils", "common" ]
-    /// ```
-    ///
-    /// #### Noteworthy
-    ///
-    /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`.
-    /// 2. Paths with any segment that containing the word 'prelude'
-    /// are already allowed by default.
-    (allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default()),
-    /// Lint: MODULE_NAME_REPETITIONS.
-    ///
-    /// List of prefixes to allow when determining whether an item's name ends with the module's name.
-    /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
-    /// then don't emit a warning.
-    ///
-    /// #### Example
-    ///
-    /// ```toml
-    /// allowed-prefixes = [ "to", "from" ]
-    /// ```
-    ///
-    /// #### Noteworthy
-    ///
-    /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
-    /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
-    ///   `TryInto` will also be included)
-    /// - Use `".."` as part of the list to indicate that the configured values should be appended to the
-    /// default configuration of Clippy. By default, any configuration will replace the default value
-    (allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()),
-    /// Lint: RENAMED_FUNCTION_PARAMS.
-    ///
-    /// List of trait paths to ignore when checking renamed function parameters.
-    ///
-    /// #### Example
-    ///
-    /// ```toml
-    /// allow-renamed-params-for = [ "std::convert::From" ]
-    /// ```
-    ///
-    /// #### Noteworthy
-    ///
-    /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr`
-    /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the
-    /// default configuration of Clippy. By default, any configuration will replace the default value.
-    (allow_renamed_params_for: Vec<String> =
-        DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect()),
-    /// Lint: MACRO_METAVARS_IN_UNSAFE.
+    #[lints(pub_underscore_fields)]
+    pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported,
+    /// Whether to lint only if it's multiline.
+    #[lints(semicolon_inside_block)]
+    semicolon_inside_block_ignore_singleline: bool = false,
+    /// Whether to lint only if it's singleline.
+    #[lints(semicolon_outside_block)]
+    semicolon_outside_block_ignore_multiline: bool = false,
+    /// The maximum number of single char bindings a scope may have
+    #[lints(many_single_char_names)]
+    single_char_binding_names_threshold: u64 = 4,
+    /// The maximum allowed stack size for functions in bytes
+    #[lints(large_stack_frames)]
+    stack_size_threshold: u64 = 512_000,
+    /// Enforce the named macros always use the braces specified.
     ///
+    /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
+    /// could be used with a full path two `MacroMatcher`s have to be added one with the full path
+    /// `crate_name::macro_name` and one with just the macro name.
+    #[lints(nonstandard_macro_braces)]
+    standard_macro_braces: Vec<MacroMatcher> = Vec::new(),
+    /// The minimum number of struct fields for the lints about field names to trigger
+    #[lints(struct_field_names)]
+    struct_field_name_threshold: u64 = 3,
+    /// Whether to suppress a restriction lint in constant code. In same
+    /// cases the restructured operation might not be unavoidable, as the
+    /// suggested counterparts are unavailable in constant code. This
+    /// configuration will cause restriction lints to trigger even
+    /// if no suggestion can be made.
+    #[lints(indexing_slicing)]
+    suppress_restriction_lint_in_const: bool = false,
+    /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
+    #[lints(boxed_local, useless_vec)]
+    too_large_for_stack: u64 = 200,
+    /// The maximum number of argument a function or method can have
+    #[lints(too_many_arguments)]
+    too_many_arguments_threshold: u64 = 7,
+    /// The maximum number of lines a function or method can have
+    #[lints(too_many_lines)]
+    too_many_lines_threshold: u64 = 100,
+    /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
+    /// reference. By default there is no limit
+    #[default_text = "target_pointer_width * 2"]
+    #[lints(trivially_copy_pass_by_ref)]
+    trivial_copy_size_limit: Option<u64> = None,
+    /// The maximum complexity a type can have
+    #[lints(type_complexity)]
+    type_complexity_threshold: u64 = 250,
+    /// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
+    #[lints(unnecessary_box_returns)]
+    unnecessary_box_size: u64 = 128,
+    /// Should the fraction of a decimal be linted to include separators.
+    #[lints(unreadable_literal)]
+    unreadable_literal_lint_fractions: bool = true,
+    /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
+    #[lints(upper_case_acronyms)]
+    upper_case_acronyms_aggressive: bool = false,
+    /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
+    #[lints(vec_box)]
+    vec_box_size_threshold: u64 = 4096,
+    /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
+    #[lints(verbose_bit_mask)]
+    verbose_bit_mask_threshold: u64 = 1,
+    /// Whether to allow certain wildcard imports (prelude, super in tests).
+    #[lints(wildcard_imports)]
+    warn_on_all_wildcard_imports: bool = false,
     /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros.
-    (warn_unsafe_macro_metavars_in_private_macros: bool = false),
+    #[lints(macro_metavars_in_unsafe)]
+    warn_unsafe_macro_metavars_in_private_macros: bool = false,
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs
index ff7fa7241cb..d2246f12029 100644
--- a/src/tools/clippy/clippy_config/src/lib.rs
+++ b/src/tools/clippy/clippy_config/src/lib.rs
@@ -1,5 +1,4 @@
-#![feature(rustc_private, let_chains)]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+#![feature(rustc_private, array_windows, let_chains)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/src/tools/clippy/clippy_config/src/metadata.rs b/src/tools/clippy/clippy_config/src/metadata.rs
index 400887185e8..7cbd92a9b71 100644
--- a/src/tools/clippy/clippy_config/src/metadata.rs
+++ b/src/tools/clippy/clippy_config/src/metadata.rs
@@ -1,11 +1,12 @@
-use std::fmt::{self, Write};
+use itertools::Itertools;
+use std::fmt;
 
 #[derive(Debug, Clone, Default)]
 pub struct ClippyConfiguration {
     pub name: String,
     pub default: String,
-    pub lints: Vec<String>,
-    pub doc: String,
+    pub lints: &'static [&'static str],
+    pub doc: &'static str,
     pub deprecation_reason: Option<&'static str>,
 }
 
@@ -13,61 +14,23 @@ impl fmt::Display for ClippyConfiguration {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "- `{}`: {}", self.name, self.doc)?;
         if !self.default.is_empty() {
-            write!(f, " (default: `{}`)", self.default)?;
+            write!(f, "\n\n   (default: `{}`)", self.default)?;
         }
         Ok(())
     }
 }
 
 impl ClippyConfiguration {
-    pub fn new(
-        name: &'static str,
-        default: String,
-        doc_comment: &'static str,
-        deprecation_reason: Option<&'static str>,
-    ) -> Self {
-        let (mut lints, doc) = parse_config_field_doc(doc_comment)
-            .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
-
-        lints.sort();
-
-        Self {
-            name: to_kebab(name),
-            lints,
-            doc,
-            default,
-            deprecation_reason,
-        }
-    }
-
     pub fn to_markdown_paragraph(&self) -> String {
-        let mut out = format!(
-            "## `{}`\n{}\n\n",
+        format!(
+            "## `{}`\n{}\n\n**Default Value:** `{}`\n\n---\n**Affected lints:**\n{}\n\n",
             self.name,
-            self.doc
-                .lines()
-                .map(|line| line.strip_prefix("    ").unwrap_or(line))
-                .collect::<Vec<_>>()
-                .join("\n"),
-        );
-
-        if !self.default.is_empty() {
-            write!(out, "**Default Value:** `{}`\n\n", self.default).unwrap();
-        }
-
-        write!(
-            out,
-            "---\n**Affected lints:**\n{}\n\n",
-            self.lints
-                .iter()
-                .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
-                .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
-                .collect::<Vec<_>>()
-                .join("\n"),
+            self.doc.lines().map(|x| x.strip_prefix(' ').unwrap_or(x)).join("\n"),
+            self.default,
+            self.lints.iter().format_with("\n", |name, f| f(&format_args!(
+                "* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"
+            ))),
         )
-        .unwrap();
-
-        out
     }
 
     pub fn to_markdown_link(&self) -> String {
@@ -75,47 +38,3 @@ impl ClippyConfiguration {
         format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name)
     }
 }
-
-/// This parses the field documentation of the config struct.
-///
-/// ```rust, ignore
-/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
-/// ```
-///
-/// Would yield:
-/// ```rust, ignore
-/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
-/// ```
-fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
-    const DOC_START: &str = " Lint: ";
-    if doc_comment.starts_with(DOC_START)
-        && let Some(split_pos) = doc_comment.find('.')
-    {
-        let mut doc_comment = doc_comment.to_string();
-        let mut documentation = doc_comment.split_off(split_pos);
-
-        // Extract lints
-        doc_comment.make_ascii_lowercase();
-        let lints: Vec<String> = doc_comment
-            .split_off(DOC_START.len())
-            .lines()
-            .next()
-            .unwrap()
-            .split(", ")
-            .map(str::to_string)
-            .collect();
-
-        // Format documentation correctly
-        // split off leading `.` from lint name list and indent for correct formatting
-        documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n    ");
-
-        Some((lints, documentation))
-    } else {
-        None
-    }
-}
-
-/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
-fn to_kebab(config_name: &str) -> String {
-    config_name.replace('_', "-")
-}
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 4104e7d94f1..a5d72c3a559 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -13,9 +13,6 @@ opener = "0.6"
 shell-escape = "0.1"
 walkdir = "2.3"
 
-[features]
-deny-warnings = []
-
 [package.metadata.rust-analyzer]
 # This package uses #[feature(rustc_private)]
 rustc_private = true
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index 25623144181..5fc4365c6e7 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -1,30 +1,65 @@
 use crate::clippy_project_root;
 use itertools::Itertools;
+use rustc_lexer::{tokenize, TokenKind};
 use shell_escape::escape;
 use std::ffi::{OsStr, OsString};
-use std::path::Path;
+use std::ops::ControlFlow;
+use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
 use std::{fs, io};
 use walkdir::WalkDir;
 
-#[derive(Debug)]
-pub enum CliError {
+pub enum Error {
     CommandFailed(String, String),
-    IoError(io::Error),
+    Io(io::Error),
     RustfmtNotInstalled,
-    WalkDirError(walkdir::Error),
+    WalkDir(walkdir::Error),
     IntellijSetupActive,
+    Parse(PathBuf, usize, String),
+    CheckFailed,
 }
 
-impl From<io::Error> for CliError {
+impl From<io::Error> for Error {
     fn from(error: io::Error) -> Self {
-        Self::IoError(error)
+        Self::Io(error)
     }
 }
 
-impl From<walkdir::Error> for CliError {
+impl From<walkdir::Error> for Error {
     fn from(error: walkdir::Error) -> Self {
-        Self::WalkDirError(error)
+        Self::WalkDir(error)
+    }
+}
+
+impl Error {
+    fn display(&self) {
+        match self {
+            Self::CheckFailed => {
+                eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update.");
+            },
+            Self::CommandFailed(command, stderr) => {
+                eprintln!("error: command `{command}` failed!\nstderr: {stderr}");
+            },
+            Self::Io(err) => {
+                eprintln!("error: {err}");
+            },
+            Self::RustfmtNotInstalled => {
+                eprintln!("error: rustfmt nightly is not installed.");
+            },
+            Self::WalkDir(err) => {
+                eprintln!("error: {err}");
+            },
+            Self::IntellijSetupActive => {
+                eprintln!(
+                    "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\
+                    Not formatting because that would format the local repo as well!\n\
+                    Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`."
+                );
+            },
+            Self::Parse(path, line, msg) => {
+                eprintln!("error parsing `{}:{line}`: {msg}", path.display());
+            },
+        }
     }
 }
 
@@ -34,75 +69,244 @@ struct FmtContext {
     rustfmt_path: String,
 }
 
-// the "main" function of cargo dev fmt
-pub fn run(check: bool, verbose: bool) {
-    fn try_run(context: &FmtContext) -> Result<bool, CliError> {
-        let mut success = true;
-
-        let project_root = clippy_project_root();
-
-        // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
-        // format because rustfmt would also format the entire rustc repo as it is a local
-        // dependency
-        if fs::read_to_string(project_root.join("Cargo.toml"))
-            .expect("Failed to read clippy Cargo.toml")
-            .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
-        {
-            return Err(CliError::IntellijSetupActive);
-        }
-
-        rustfmt_test(context)?;
+struct ClippyConf<'a> {
+    name: &'a str,
+    attrs: &'a str,
+    lints: Vec<&'a str>,
+    field: &'a str,
+}
 
-        success &= cargo_fmt(context, project_root.as_path())?;
-        success &= cargo_fmt(context, &project_root.join("clippy_dev"))?;
-        success &= cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
-        success &= cargo_fmt(context, &project_root.join("lintcheck"))?;
+fn offset_to_line(text: &str, offset: usize) -> usize {
+    match text.split('\n').try_fold((1usize, 0usize), |(line, pos), s| {
+        let pos = pos + s.len() + 1;
+        if pos > offset {
+            ControlFlow::Break(line)
+        } else {
+            ControlFlow::Continue((line + 1, pos))
+        }
+    }) {
+        ControlFlow::Break(x) | ControlFlow::Continue((x, _)) => x,
+    }
+}
 
-        let chunks = WalkDir::new(project_root.join("tests"))
-            .into_iter()
-            .filter_map(|entry| {
-                let entry = entry.expect("failed to find tests");
-                let path = entry.path();
+/// Formats the configuration list in `clippy_config/src/conf.rs`
+#[expect(clippy::too_many_lines)]
+fn fmt_conf(check: bool) -> Result<(), Error> {
+    #[derive(Clone, Copy)]
+    enum State {
+        Start,
+        Docs,
+        Pound,
+        OpenBracket,
+        Attr(u32),
+        Lints,
+        EndLints,
+        Field,
+    }
 
-                if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
-                    None
-                } else {
-                    Some(entry.into_path().into_os_string())
-                }
-            })
-            .chunks(250);
+    let path: PathBuf = [
+        clippy_project_root().as_path(),
+        "clippy_config".as_ref(),
+        "src".as_ref(),
+        "conf.rs".as_ref(),
+    ]
+    .into_iter()
+    .collect();
+    let text = fs::read_to_string(&path)?;
 
-        for chunk in &chunks {
-            success &= rustfmt(context, chunk)?;
-        }
+    let (pre, conf) = text
+        .split_once("define_Conf! {\n")
+        .expect("can't find config definition");
+    let (conf, post) = conf.split_once("\n}\n").expect("can't find config definition");
+    let conf_offset = pre.len() + 15;
 
-        Ok(success)
-    }
+    let mut pos = 0u32;
+    let mut attrs_start = 0;
+    let mut attrs_end = 0;
+    let mut field_start = 0;
+    let mut lints = Vec::new();
+    let mut name = "";
+    let mut fields = Vec::new();
+    let mut state = State::Start;
 
-    fn output_err(err: CliError) {
-        match err {
-            CliError::CommandFailed(command, stderr) => {
-                eprintln!("error: A command failed! `{command}`\nstderr: {stderr}");
+    for (i, t) in tokenize(conf)
+        .map(|x| {
+            let start = pos;
+            pos += x.len;
+            (start as usize, x)
+        })
+        .filter(|(_, t)| !matches!(t.kind, TokenKind::Whitespace))
+    {
+        match (state, t.kind) {
+            (State::Start, TokenKind::LineComment { doc_style: Some(_) }) => {
+                attrs_start = i;
+                attrs_end = i + t.len as usize;
+                state = State::Docs;
             },
-            CliError::IoError(err) => {
-                eprintln!("error: {err}");
+            (State::Start, TokenKind::Pound) => {
+                attrs_start = i;
+                attrs_end = i;
+                state = State::Pound;
             },
-            CliError::RustfmtNotInstalled => {
-                eprintln!("error: rustfmt nightly is not installed.");
+            (State::Docs, TokenKind::LineComment { doc_style: Some(_) }) => attrs_end = i + t.len as usize,
+            (State::Docs, TokenKind::Pound) => state = State::Pound,
+            (State::Pound, TokenKind::OpenBracket) => state = State::OpenBracket,
+            (State::OpenBracket, TokenKind::Ident) => {
+                state = if conf[i..i + t.len as usize] == *"lints" {
+                    State::Lints
+                } else {
+                    State::Attr(0)
+                };
             },
-            CliError::WalkDirError(err) => {
-                eprintln!("error: {err}");
+            (State::Attr(0), TokenKind::CloseBracket) => {
+                attrs_end = i + 1;
+                state = State::Docs;
             },
-            CliError::IntellijSetupActive => {
-                eprintln!(
-                    "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.
-Not formatting because that would format the local repo as well!
-Please revert the changes to Cargo.tomls with `cargo dev remove intellij`."
-                );
+            (State::Attr(x), TokenKind::OpenParen | TokenKind::OpenBracket | TokenKind::OpenBrace) => {
+                state = State::Attr(x + 1);
+            },
+            (State::Attr(x), TokenKind::CloseParen | TokenKind::CloseBracket | TokenKind::CloseBrace) => {
+                state = State::Attr(x - 1);
+            },
+            (State::Lints, TokenKind::Ident) => lints.push(&conf[i..i + t.len as usize]),
+            (State::Lints, TokenKind::CloseBracket) => state = State::EndLints,
+            (State::EndLints | State::Docs, TokenKind::Ident) => {
+                field_start = i;
+                name = &conf[i..i + t.len as usize];
+                state = State::Field;
+            },
+            (State::Field, TokenKind::LineComment { doc_style: Some(_) }) => {
+                #[expect(clippy::drain_collect)]
+                fields.push(ClippyConf {
+                    name,
+                    lints: lints.drain(..).collect(),
+                    attrs: &conf[attrs_start..attrs_end],
+                    field: conf[field_start..i].trim_end(),
+                });
+                attrs_start = i;
+                attrs_end = i + t.len as usize;
+                state = State::Docs;
+            },
+            (State::Field, TokenKind::Pound) => {
+                #[expect(clippy::drain_collect)]
+                fields.push(ClippyConf {
+                    name,
+                    lints: lints.drain(..).collect(),
+                    attrs: &conf[attrs_start..attrs_end],
+                    field: conf[field_start..i].trim_end(),
+                });
+                attrs_start = i;
+                attrs_end = i;
+                state = State::Pound;
+            },
+            (State::Field | State::Attr(_), _)
+            | (State::Lints, TokenKind::Comma | TokenKind::OpenParen | TokenKind::CloseParen) => {},
+            _ => {
+                return Err(Error::Parse(
+                    path,
+                    offset_to_line(&text, conf_offset + i),
+                    format!("unexpected token `{}`", &conf[i..i + t.len as usize]),
+                ));
             },
         }
     }
 
+    if !matches!(state, State::Field) {
+        return Err(Error::Parse(
+            path,
+            offset_to_line(&text, conf_offset + conf.len()),
+            "incomplete field".into(),
+        ));
+    }
+    fields.push(ClippyConf {
+        name,
+        lints,
+        attrs: &conf[attrs_start..attrs_end],
+        field: conf[field_start..].trim_end(),
+    });
+
+    for field in &mut fields {
+        field.lints.sort_unstable();
+    }
+    fields.sort_by_key(|x| x.name);
+
+    let new_text = format!(
+        "{pre}define_Conf! {{\n{}}}\n{post}",
+        fields.iter().format_with("", |field, f| {
+            if field.lints.is_empty() {
+                f(&format_args!("    {}\n    {}\n", field.attrs, field.field))
+            } else if field.lints.iter().map(|x| x.len() + 2).sum::<usize>() < 120 - 14 {
+                f(&format_args!(
+                    "    {}\n    #[lints({})]\n    {}\n",
+                    field.attrs,
+                    field.lints.iter().join(", "),
+                    field.field,
+                ))
+            } else {
+                f(&format_args!(
+                    "    {}\n    #[lints({}\n    )]\n    {}\n",
+                    field.attrs,
+                    field
+                        .lints
+                        .iter()
+                        .format_with("", |x, f| f(&format_args!("\n        {x},"))),
+                    field.field,
+                ))
+            }
+        })
+    );
+
+    if text != new_text {
+        if check {
+            return Err(Error::CheckFailed);
+        }
+        fs::write(&path, new_text.as_bytes())?;
+    }
+    Ok(())
+}
+
+fn run_rustfmt(context: &FmtContext) -> Result<(), Error> {
+    let project_root = clippy_project_root();
+
+    // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
+    // format because rustfmt would also format the entire rustc repo as it is a local
+    // dependency
+    if fs::read_to_string(project_root.join("Cargo.toml"))
+        .expect("Failed to read clippy Cargo.toml")
+        .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
+    {
+        return Err(Error::IntellijSetupActive);
+    }
+
+    check_for_rustfmt(context)?;
+
+    cargo_fmt(context, project_root.as_path())?;
+    cargo_fmt(context, &project_root.join("clippy_dev"))?;
+    cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
+    cargo_fmt(context, &project_root.join("lintcheck"))?;
+
+    let chunks = WalkDir::new(project_root.join("tests"))
+        .into_iter()
+        .filter_map(|entry| {
+            let entry = entry.expect("failed to find tests");
+            let path = entry.path();
+
+            if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
+                None
+            } else {
+                Some(entry.into_path().into_os_string())
+            }
+        })
+        .chunks(250);
+
+    for chunk in &chunks {
+        rustfmt(context, chunk)?;
+    }
+    Ok(())
+}
+
+// the "main" function of cargo dev fmt
+pub fn run(check: bool, verbose: bool) {
     let output = Command::new("rustup")
         .args(["which", "rustfmt"])
         .stderr(Stdio::inherit())
@@ -120,21 +324,10 @@ Please revert the changes to Cargo.tomls with `cargo dev remove intellij`."
         verbose,
         rustfmt_path,
     };
-    let result = try_run(&context);
-    let code = match result {
-        Ok(true) => 0,
-        Ok(false) => {
-            eprintln!();
-            eprintln!("Formatting check failed.");
-            eprintln!("Run `cargo dev fmt` to update formatting.");
-            1
-        },
-        Err(err) => {
-            output_err(err);
-            1
-        },
-    };
-    process::exit(code);
+    if let Err(e) = run_rustfmt(&context).and_then(|()| fmt_conf(check)) {
+        e.display();
+        process::exit(1);
+    }
 }
 
 fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[impl AsRef<OsStr>]) -> String {
@@ -148,12 +341,12 @@ fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[imp
     )
 }
 
-fn exec(
+fn exec_fmt_command(
     context: &FmtContext,
     program: impl AsRef<OsStr>,
     dir: impl AsRef<Path>,
     args: &[impl AsRef<OsStr>],
-) -> Result<bool, CliError> {
+) -> Result<(), Error> {
     if context.verbose {
         println!("{}", format_command(&program, &dir, args));
     }
@@ -166,28 +359,28 @@ fn exec(
         .unwrap();
     let success = output.status.success();
 
-    if !context.check && !success {
-        let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
-        return Err(CliError::CommandFailed(
-            format_command(&program, &dir, args),
-            String::from(stderr),
-        ));
+    match (context.check, success) {
+        (_, true) => Ok(()),
+        (true, false) => Err(Error::CheckFailed),
+        (false, false) => {
+            let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
+            Err(Error::CommandFailed(
+                format_command(&program, &dir, args),
+                String::from(stderr),
+            ))
+        },
     }
-
-    Ok(success)
 }
 
-fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
+fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<(), Error> {
     let mut args = vec!["fmt", "--all"];
     if context.check {
         args.push("--check");
     }
-    let success = exec(context, "cargo", path, &args)?;
-
-    Ok(success)
+    exec_fmt_command(context, "cargo", path, &args)
 }
 
-fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
+fn check_for_rustfmt(context: &FmtContext) -> Result<(), Error> {
     let program = "rustfmt";
     let dir = std::env::current_dir()?;
     let args = &["--version"];
@@ -204,23 +397,20 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
         .unwrap_or("")
         .starts_with("error: 'rustfmt' is not installed")
     {
-        Err(CliError::RustfmtNotInstalled)
+        Err(Error::RustfmtNotInstalled)
     } else {
-        Err(CliError::CommandFailed(
+        Err(Error::CommandFailed(
             format_command(program, &dir, args),
             std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
         ))
     }
 }
 
-fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Result<bool, CliError> {
+fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Result<(), Error> {
     let mut args = Vec::new();
     if context.check {
         args.push(OsString::from("--check"));
     }
     args.extend(paths);
-
-    let success = exec(context, &context.rustfmt_path, std::env::current_dir()?, &args)?;
-
-    Ok(success)
+    exec_fmt_command(context, &context.rustfmt_path, std::env::current_dir()?, &args)
 }
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 3aa43dbe23e..ad385d5fbd2 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(let_chains)]
 #![feature(rustc_private)]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 366b52b25df..755b04b0b23 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
@@ -74,7 +73,7 @@ fn main() {
             new_name,
             uplift,
         } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift),
-        DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, reason.as_deref()),
+        DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason),
     }
 }
 
@@ -223,7 +222,7 @@ enum DevCommand {
         name: String,
         #[arg(long, short)]
         /// The reason for deprecation
-        reason: Option<String>,
+        reason: String,
     },
 }
 
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index 4a4261d1a1e..19560b31fd3 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -1,10 +1,14 @@
-use std::ffi::OsStr;
-use std::num::ParseIntError;
 use std::path::Path;
 use std::process::Command;
 use std::time::{Duration, SystemTime};
 use std::{env, thread};
 
+#[cfg(windows)]
+const PYTHON: &str = "python";
+
+#[cfg(not(windows))]
+const PYTHON: &str = "python3";
+
 /// # Panics
 ///
 /// Panics if the python commands could not be spawned
@@ -25,7 +29,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
         }
         if let Some(url) = url.take() {
             thread::spawn(move || {
-                Command::new("python3")
+                Command::new(PYTHON)
                     .arg("-m")
                     .arg("http.server")
                     .arg(port.to_string())
@@ -58,8 +62,3 @@ fn mtime(path: impl AsRef<Path>) -> SystemTime {
             .unwrap_or(SystemTime::UNIX_EPOCH)
     }
 }
-
-#[allow(clippy::missing_errors_doc)]
-pub fn validate_port(arg: &OsStr) -> Result<(), ParseIntError> {
-    arg.to_string_lossy().parse::<u16>().map(|_| ())
-}
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 45353901c98..15578d69c3a 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -1,13 +1,12 @@
 use crate::clippy_project_root;
 use aho_corasick::AhoCorasickBuilder;
-use indoc::writedoc;
 use itertools::Itertools;
 use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 use std::collections::{HashMap, HashSet};
 use std::ffi::OsStr;
 use std::fmt::{self, Write};
 use std::fs::{self, OpenOptions};
-use std::io::{self, Read, Seek, SeekFrom, Write as _};
+use std::io::{self, Read, Seek, Write as _};
 use std::ops::Range;
 use std::path::{Path, PathBuf};
 use walkdir::{DirEntry, WalkDir};
@@ -77,12 +76,8 @@ fn generate_lint_files(
             for lint in usable_lints
                 .iter()
                 .map(|l| &*l.name)
-                .chain(deprecated_lints.iter().map(|l| &*l.name))
-                .chain(
-                    renamed_lints
-                        .iter()
-                        .map(|l| l.old_name.strip_prefix("clippy::").unwrap_or(&l.old_name)),
-                )
+                .chain(deprecated_lints.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
+                .chain(renamed_lints.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
                 .sorted()
             {
                 writeln!(res, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
@@ -108,11 +103,6 @@ fn generate_lint_files(
         update_mode,
         &gen_declared_lints(internal_lints.iter(), usable_lints.iter()),
     );
-    process_file(
-        "clippy_lints/src/lib.deprecated.rs",
-        update_mode,
-        &gen_deprecated(deprecated_lints),
-    );
 
     let content = gen_deprecated_lints_test(deprecated_lints);
     process_file("tests/ui/deprecated.rs", update_mode, &content);
@@ -205,7 +195,7 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
             let ext = f.path().extension();
             (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed")))
                 && name != Some(OsStr::new("rename.rs"))
-                && name != Some(OsStr::new("renamed_lints.rs"))
+                && name != Some(OsStr::new("deprecated_lints.rs"))
         })
     {
         rewrite_file(file.path(), |s| {
@@ -213,6 +203,19 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
         });
     }
 
+    let version = crate::new_lint::get_stabilization_version();
+    rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| {
+        insert_at_marker(
+            s,
+            "// end renamed lints. used by `cargo dev rename_lint`",
+            &format!(
+                "#[clippy::version = \"{version}\"]\n    \
+                (\"{}\", \"{}\"),\n    ",
+                lint.old_name, lint.new_name,
+            ),
+        )
+    });
+
     renamed_lints.push(lint);
     renamed_lints.sort_by(|lhs, rhs| {
         lhs.new_name
@@ -222,11 +225,6 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
             .then_with(|| lhs.old_name.cmp(&rhs.old_name))
     });
 
-    write_file(
-        Path::new("clippy_lints/src/renamed_lints.rs"),
-        &gen_renamed_lints_list(&renamed_lints),
-    );
-
     if uplift {
         write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints));
         println!(
@@ -293,7 +291,8 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
 
         // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being
         // renamed.
-        for (_, file) in clippy_lints_src_files().filter(|(rel_path, _)| rel_path != OsStr::new("renamed_lints.rs")) {
+        for (_, file) in clippy_lints_src_files().filter(|(rel_path, _)| rel_path != OsStr::new("deprecated_lints.rs"))
+        {
             rewrite_file(file.path(), |s| replace_ident_like(s, replacements));
         }
 
@@ -304,7 +303,6 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
     println!("note: `cargo uitest` still needs to be run to update the test results");
 }
 
-const DEFAULT_DEPRECATION_REASON: &str = "default deprecation note";
 /// Runs the `deprecate` command
 ///
 /// This does the following:
@@ -314,33 +312,16 @@ const DEFAULT_DEPRECATION_REASON: &str = "default deprecation note";
 /// # Panics
 ///
 /// If a file path could not read from or written to
-pub fn deprecate(name: &str, reason: Option<&str>) {
-    fn finish(
-        (lints, mut deprecated_lints, renamed_lints): (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>),
-        name: &str,
-        reason: &str,
-    ) {
-        deprecated_lints.push(DeprecatedLint {
-            name: name.to_string(),
-            reason: reason.to_string(),
-            declaration_range: Range::default(),
-        });
-
-        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
-        println!("info: `{name}` has successfully been deprecated");
-
-        if reason == DEFAULT_DEPRECATION_REASON {
-            println!("note: the deprecation reason must be updated in `clippy_lints/src/deprecated_lints.rs`");
-        }
-        println!("note: you must run `cargo uitest` to update the test results");
-    }
-
-    let reason = reason.unwrap_or(DEFAULT_DEPRECATION_REASON);
-    let name_lower = name.to_lowercase();
-    let name_upper = name.to_uppercase();
+pub fn deprecate(name: &str, reason: &str) {
+    let prefixed_name = if name.starts_with("clippy::") {
+        name.to_owned()
+    } else {
+        format!("clippy::{name}")
+    };
+    let stripped_name = &prefixed_name[8..];
 
-    let (mut lints, deprecated_lints, renamed_lints) = gather_all();
-    let Some(lint) = lints.iter().find(|l| l.name == name_lower) else {
+    let (mut lints, mut deprecated_lints, renamed_lints) = gather_all();
+    let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else {
         eprintln!("error: failed to find lint `{name}`");
         return;
     };
@@ -357,13 +338,27 @@ pub fn deprecate(name: &str, reason: Option<&str>) {
 
     let deprecated_lints_path = &*clippy_project_root().join("clippy_lints/src/deprecated_lints.rs");
 
-    if remove_lint_declaration(&name_lower, &mod_path, &mut lints).unwrap_or(false) {
-        declare_deprecated(&name_upper, deprecated_lints_path, reason).unwrap();
-        finish((lints, deprecated_lints, renamed_lints), name, reason);
-        return;
-    }
+    if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) {
+        let version = crate::new_lint::get_stabilization_version();
+        rewrite_file(deprecated_lints_path, |s| {
+            insert_at_marker(
+                s,
+                "// end deprecated lints. used by `cargo dev deprecate_lint`",
+                &format!("#[clippy::version = \"{version}\"]\n    (\"{prefixed_name}\", \"{reason}\"),\n    ",),
+            )
+        });
+
+        deprecated_lints.push(DeprecatedLint {
+            name: prefixed_name,
+            reason: reason.into(),
+        });
 
-    eprintln!("error: lint not found");
+        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
+        println!("info: `{name}` has successfully been deprecated");
+        println!("note: you must run `cargo uitest` to update the test results");
+    } else {
+        eprintln!("error: lint not found");
+    }
 }
 
 fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io::Result<bool> {
@@ -377,14 +372,14 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
 
         // Some lints have their own directories, delete them
         if path.is_dir() {
-            fs::remove_dir_all(path).ok();
+            let _ = fs::remove_dir_all(path);
             return;
         }
 
         // Remove all related test files
-        fs::remove_file(path.with_extension("rs")).ok();
-        fs::remove_file(path.with_extension("stderr")).ok();
-        fs::remove_file(path.with_extension("fixed")).ok();
+        let _ = fs::remove_file(path.with_extension("rs"));
+        let _ = fs::remove_file(path.with_extension("stderr"));
+        let _ = fs::remove_file(path.with_extension("fixed"));
     }
 
     fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) {
@@ -427,7 +422,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
                     lint_mod_path.set_file_name(name);
                     lint_mod_path.set_extension("rs");
 
-                    fs::remove_file(lint_mod_path).ok();
+                    let _ = fs::remove_file(lint_mod_path);
                 }
 
                 let mut content =
@@ -465,37 +460,6 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
     Ok(false)
 }
 
-fn declare_deprecated(name: &str, path: &Path, reason: &str) -> io::Result<()> {
-    let mut file = OpenOptions::new().write(true).open(path)?;
-
-    file.seek(SeekFrom::End(0))?;
-
-    let version = crate::new_lint::get_stabilization_version();
-    let deprecation_reason = if reason == DEFAULT_DEPRECATION_REASON {
-        "TODO"
-    } else {
-        reason
-    };
-
-    writedoc!(
-        file,
-        "
-
-        declare_deprecated_lint! {{
-            /// ### What it does
-            /// Nothing. This lint has been deprecated.
-            ///
-            /// ### Deprecation reason
-            /// {deprecation_reason}
-            #[clippy::version = \"{version}\"]
-            pub {name},
-            \"{reason}\"
-        }}
-
-        "
-    )
-}
-
 /// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there
 /// were no replacements.
 fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option<String> {
@@ -604,14 +568,12 @@ impl Lint {
 struct DeprecatedLint {
     name: String,
     reason: String,
-    declaration_range: Range<usize>,
 }
 impl DeprecatedLint {
-    fn new(name: &str, reason: &str, declaration_range: Range<usize>) -> Self {
+    fn new(name: &str, reason: &str) -> Self {
         Self {
-            name: name.to_lowercase(),
+            name: remove_line_splices(name),
             reason: remove_line_splices(reason),
-            declaration_range,
         }
     }
 }
@@ -629,28 +591,6 @@ impl RenamedLint {
     }
 }
 
-/// Generates the `register_removed` code
-#[must_use]
-fn gen_deprecated(lints: &[DeprecatedLint]) -> String {
-    let mut output = GENERATED_FILE_COMMENT.to_string();
-    output.push_str("{\n");
-    for lint in lints {
-        let _: fmt::Result = write!(
-            output,
-            concat!(
-                "    store.register_removed(\n",
-                "        \"clippy::{}\",\n",
-                "        \"{}\",\n",
-                "    );\n"
-            ),
-            lint.name, lint.reason,
-        );
-    }
-    output.push_str("}\n");
-
-    output
-}
-
 /// Generates the code for registering lints
 #[must_use]
 fn gen_declared_lints<'a>(
@@ -680,7 +620,7 @@ fn gen_declared_lints<'a>(
 fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String {
     let mut res: String = GENERATED_FILE_COMMENT.into();
     for lint in lints {
-        writeln!(res, "#![warn(clippy::{})]", lint.name).unwrap();
+        writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
     }
     res.push_str("\nfn main() {}\n");
     res
@@ -699,27 +639,13 @@ fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String {
     seen_lints.clear();
     for lint in lints {
         if seen_lints.insert(&lint.old_name) {
-            writeln!(res, "#![warn({})]", lint.old_name).unwrap();
+            writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
         }
     }
     res.push_str("\nfn main() {}\n");
     res
 }
 
-fn gen_renamed_lints_list(lints: &[RenamedLint]) -> String {
-    const HEADER: &str = "\
-        // This file is managed by `cargo dev rename_lint`. Prefer using that when possible.\n\n\
-        #[rustfmt::skip]\n\
-        pub static RENAMED_LINTS: &[(&str, &str)] = &[\n";
-
-    let mut res = String::from(HEADER);
-    for lint in lints {
-        writeln!(res, "    (\"{}\", \"{}\"),", lint.old_name, lint.new_name).unwrap();
-    }
-    res.push_str("];\n");
-    res
-}
-
 /// Gathers all lints defined in `clippy_lints/src`
 fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>) {
     let mut lints = Vec::with_capacity(1000);
@@ -744,10 +670,10 @@ fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>) {
             module.strip_suffix(".rs").unwrap_or(&module)
         };
 
-        match module {
-            "deprecated_lints" => parse_deprecated_contents(&contents, &mut deprecated_lints),
-            "renamed_lints" => parse_renamed_contents(&contents, &mut renamed_lints),
-            _ => parse_contents(&contents, module, &mut lints),
+        if module == "deprecated_lints" {
+            parse_deprecated_contents(&contents, &mut deprecated_lints, &mut renamed_lints);
+        } else {
+            parse_contents(&contents, module, &mut lints);
         }
     }
     (lints, deprecated_lints, renamed_lints)
@@ -848,54 +774,37 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
 }
 
 /// Parse a source file looking for `declare_deprecated_lint` macro invocations.
-fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) {
-    let mut offset = 0usize;
-    let mut iter = tokenize(contents).map(|t| {
-        let range = offset..offset + t.len as usize;
-        offset = range.end;
-
-        LintDeclSearchResult {
-            token_kind: t.kind,
-            content: &contents[range.clone()],
-            range,
-        }
-    });
+fn parse_deprecated_contents(contents: &str, deprecated: &mut Vec<DeprecatedLint>, renamed: &mut Vec<RenamedLint>) {
+    let Some((_, contents)) = contents.split_once("\ndeclare_with_version! { DEPRECATED") else {
+        return;
+    };
+    let Some((deprecated_src, renamed_src)) = contents.split_once("\ndeclare_with_version! { RENAMED") else {
+        return;
+    };
 
-    while let Some(LintDeclSearchResult { range, .. }) = iter.find(
-        |LintDeclSearchResult {
-             token_kind, content, ..
-         }| token_kind == &TokenKind::Ident && *content == "declare_deprecated_lint",
-    ) {
-        let start = range.start;
+    for line in deprecated_src.lines() {
+        let mut offset = 0usize;
+        let mut iter = tokenize(line).map(|t| {
+            let range = offset..offset + t.len as usize;
+            offset = range.end;
 
-        let mut iter = iter.by_ref().filter(|LintDeclSearchResult { ref token_kind, .. }| {
-            !matches!(token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })
+            LintDeclSearchResult {
+                token_kind: t.kind,
+                content: &line[range.clone()],
+                range,
+            }
         });
+
         let (name, reason) = match_tokens!(
             iter,
-            // !{
-            Bang OpenBrace
-            // #[clippy::version = "version"]
-            Pound OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket
-            // pub LINT_NAME,
-            Ident Ident(name) Comma
-            // "description"
-            Literal{kind: LiteralKind::Str{..},..}(reason)
+            // ("old_name",
+            Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(name) Comma
+            // "new_name"),
+            Whitespace Literal{kind: LiteralKind::Str{..},..}(reason) CloseParen Comma
         );
-
-        if let Some(LintDeclSearchResult {
-            token_kind: TokenKind::CloseBrace,
-            range,
-            ..
-        }) = iter.next()
-        {
-            lints.push(DeprecatedLint::new(name, reason, start..range.end));
-        }
+        deprecated.push(DeprecatedLint::new(name, reason));
     }
-}
-
-fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) {
-    for line in contents.lines() {
+    for line in renamed_src.lines() {
         let mut offset = 0usize;
         let mut iter = tokenize(line).map(|t| {
             let range = offset..offset + t.len as usize;
@@ -915,7 +824,7 @@ fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) {
             // "new_name"),
             Whitespace Literal{kind: LiteralKind::Str{..},..}(new_name) CloseParen Comma
         );
-        lints.push(RenamedLint::new(old_name, new_name));
+        renamed.push(RenamedLint::new(old_name, new_name));
     }
 }
 
@@ -1015,6 +924,12 @@ fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
     panic!("failed to {action} file `{}`: {error}", name.display())
 }
 
+fn insert_at_marker(text: &str, marker: &str, new_text: &str) -> Option<String> {
+    let i = text.find(marker)?;
+    let (pre, post) = text.split_at(i);
+    Some([pre, new_text, post].into_iter().collect())
+}
+
 fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {
     let mut file = OpenOptions::new()
         .write(true)
@@ -1085,31 +1000,6 @@ mod tests {
     }
 
     #[test]
-    fn test_parse_deprecated_contents() {
-        static DEPRECATED_CONTENTS: &str = r#"
-            /// some doc comment
-            declare_deprecated_lint! {
-                #[clippy::version = "I'm a version"]
-                pub SHOULD_ASSERT_EQ,
-                "`assert!()` will be more flexible with RFC 2011"
-            }
-        "#;
-
-        let mut result = Vec::new();
-        parse_deprecated_contents(DEPRECATED_CONTENTS, &mut result);
-        for r in &mut result {
-            r.declaration_range = Range::default();
-        }
-
-        let expected = vec![DeprecatedLint::new(
-            "should_assert_eq",
-            "\"`assert!()` will be more flexible with RFC 2011\"",
-            Range::default(),
-        )];
-        assert_eq!(expected, result);
-    }
-
-    #[test]
     fn test_usable_lints() {
         let lints = vec![
             Lint::new(
@@ -1177,34 +1067,4 @@ mod tests {
         );
         assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
     }
-
-    #[test]
-    fn test_gen_deprecated() {
-        let lints = vec![
-            DeprecatedLint::new(
-                "should_assert_eq",
-                "\"has been superseded by should_assert_eq2\"",
-                Range::default(),
-            ),
-            DeprecatedLint::new("another_deprecated", "\"will be removed\"", Range::default()),
-        ];
-
-        let expected = GENERATED_FILE_COMMENT.to_string()
-            + &[
-                "{",
-                "    store.register_removed(",
-                "        \"clippy::should_assert_eq\",",
-                "        \"has been superseded by should_assert_eq2\",",
-                "    );",
-                "    store.register_removed(",
-                "        \"clippy::another_deprecated\",",
-                "        \"will be removed\",",
-                "    );",
-                "}",
-            ]
-            .join("\n")
-            + "\n";
-
-        assert_eq!(expected, gen_deprecated(&lints));
-    }
 }
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index eb04c006f89..99ed93468a0 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -32,7 +32,6 @@ url = "2.2"
 walkdir = "2.3"
 
 [features]
-deny-warnings = ["clippy_config/deny-warnings", "clippy_utils/deny-warnings"]
 # build clippy with internal lints enabled, off by default
 internal = ["serde_json", "tempfile", "regex"]
 
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index e6d52bcef71..3b4cc113480 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -97,7 +97,7 @@ impl ApproxConstant {
                         cx,
                         APPROX_CONSTANT,
                         e.span,
-                        format!("approximate value of `{module}::consts::{}` found", &name),
+                        format!("approximate value of `{module}::consts::{name}` found"),
                         None,
                         "consider using the constant directly",
                     );
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index cfa25005a05..fefd8195f8e 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -52,13 +52,15 @@ impl<'tcx> LateLintPass<'tcx> for AsConversions {
             && !in_external_macro(cx.sess(), expr.span)
             && !is_from_proc_macro(cx, expr)
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 AS_CONVERSIONS,
                 expr.span,
                 "using a potentially dangerous silent `as` conversion",
-                None,
-                "consider using a safe wrapper for this conversion",
+                |diag| {
+                    diag.help("consider using a safe wrapper for this conversion");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
index 0db1456d40b..69a8eb7d94e 100644
--- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs
+++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
@@ -1,6 +1,6 @@
 use std::fmt;
 
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions};
 use rustc_ast::{InlineAsm, Item, ItemKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
@@ -49,14 +49,10 @@ fn check_asm_syntax(
         };
 
         if style == check_for {
-            span_lint_and_help(
-                cx,
-                lint,
-                span,
-                format!("{style} x86 assembly syntax used"),
-                None,
-                format!("use {} x86 assembly syntax", !style),
-            );
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(cx, lint, span, format!("{style} x86 assembly syntax used"), |diag| {
+                diag.help(format!("use {} x86 assembly syntax", !style));
+            });
         }
     }
 }
@@ -98,13 +94,13 @@ declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]);
 impl EarlyLintPass for InlineAsmX86IntelSyntax {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::InlineAsm(inline_asm) = &expr.kind {
-            check_asm_syntax(Self::get_lints()[0], cx, inline_asm, expr.span, AsmStyle::Intel);
+            check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, expr.span, AsmStyle::Intel);
         }
     }
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
         if let ItemKind::GlobalAsm(inline_asm) = &item.kind {
-            check_asm_syntax(Self::get_lints()[0], cx, inline_asm, item.span, AsmStyle::Intel);
+            check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, item.span, AsmStyle::Intel);
         }
     }
 }
@@ -146,13 +142,13 @@ declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]);
 impl EarlyLintPass for InlineAsmX86AttSyntax {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::InlineAsm(inline_asm) = &expr.kind {
-            check_asm_syntax(Self::get_lints()[0], cx, inline_asm, expr.span, AsmStyle::Att);
+            check_asm_syntax(INLINE_ASM_X86_ATT_SYNTAX, cx, inline_asm, expr.span, AsmStyle::Att);
         }
     }
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
         if let ItemKind::GlobalAsm(inline_asm) = &item.kind {
-            check_asm_syntax(Self::get_lints()[0], cx, inline_asm, item.span, AsmStyle::Att);
+            check_asm_syntax(INLINE_ASM_X86_ATT_SYNTAX, cx, inline_asm, item.span, AsmStyle::Att);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index ed4cdce8cb8..7eaac80f969 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_inside_always_const_context;
 use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
         let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
             return;
         };
-        let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
+        let Some(Constant::Bool(val)) = ConstEvalCtxt::new(cx).eval(condition) else {
             return;
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index 7217686dcca..f1cb4a05af8 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
@@ -68,39 +68,28 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                     return;
                 }
             }
-            let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" };
-            let mut app = Applicability::MachineApplicable;
-            match method_segment.ident.as_str() {
+            let (message, replacement) = match method_segment.ident.as_str() {
                 "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
-                    span_lint_and_sugg(
-                        cx,
-                        ASSERTIONS_ON_RESULT_STATES,
-                        macro_call.span,
-                        "called `assert!` with `Result::is_ok`",
-                        "replace with",
-                        format!(
-                            "{}.unwrap(){semicolon}",
-                            snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
-                        ),
-                        app,
-                    );
+                    ("called `assert!` with `Result::is_ok`", "unwrap")
                 },
                 "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
-                    span_lint_and_sugg(
-                        cx,
-                        ASSERTIONS_ON_RESULT_STATES,
-                        macro_call.span,
-                        "called `assert!` with `Result::is_err`",
-                        "replace with",
-                        format!(
-                            "{}.unwrap_err(){semicolon}",
-                            snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
-                        ),
-                        app,
-                    );
+                    ("called `assert!` with `Result::is_err`", "unwrap_err")
                 },
-                _ => (),
+                _ => return,
             };
+            span_lint_and_then(cx, ASSERTIONS_ON_RESULT_STATES, macro_call.span, message, |diag| {
+                let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" };
+                let mut app = Applicability::MachineApplicable;
+                diag.span_suggestion(
+                    macro_call.span,
+                    "replace with",
+                    format!(
+                        "{}.{replacement}(){semicolon}",
+                        snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
+                    ),
+                    app,
+                );
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 03f777600f0..6e336efbb90 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -227,9 +227,22 @@ fn build_sugg<'tcx>(
             match call_kind {
                 CallKind::Method => {
                     let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                        // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
-                        Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                        // If `ref_expr` is a reference, we can remove the dereference operator (`*`) to make
+                        // the generated code a bit simpler. In other cases, we don't do this special case, to avoid
+                        // having to deal with Deref (https://github.com/rust-lang/rust-clippy/issues/12437).
+
+                        let ty = cx.typeck_results().expr_ty(ref_expr);
+                        if ty.is_ref() {
+                            // Apply special case, remove `*`
+                            // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
+                            Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                        } else {
+                            // Keep the original lhs
+                            // `*lhs = self_expr.clone();` -> `(*lhs).clone_from(self_expr)`
+                            Sugg::hir_with_applicability(cx, lhs, "_", app)
+                        }
                     } else {
+                        // Keep the original lhs
                         // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
                         Sugg::hir_with_applicability(cx, lhs, "_", app)
                     }
@@ -249,8 +262,16 @@ fn build_sugg<'tcx>(
                 },
                 CallKind::Ufcs => {
                     let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                        // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
-                        Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                        // See special case of removing `*` in method handling above
+                        let ty = cx.typeck_results().expr_ty(ref_expr);
+                        if ty.is_ref() {
+                            // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
+                            Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                        } else {
+                            // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut *lhs, self_expr)`
+                            // mut_addr_deref is used to avoid unnecessary parentheses around `*lhs`
+                            Sugg::hir_with_applicability(cx, ref_expr, "_", app).mut_addr_deref()
+                        }
                     } else {
                         // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
                         Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr()
diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
index df9994086cd..a5a7b9f74a6 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
@@ -1,5 +1,5 @@
 use super::ALLOW_ATTRIBUTES;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_ast::{AttrStyle, Attribute};
 use rustc_errors::Applicability;
@@ -13,14 +13,14 @@ pub fn check<'cx>(cx: &LateContext<'cx>, attr: &'cx Attribute) {
         && let Some(ident) = attr.ident()
         && !is_from_proc_macro(cx, attr)
     {
-        span_lint_and_sugg(
-            cx,
-            ALLOW_ATTRIBUTES,
-            ident.span,
-            "#[allow] attribute found",
-            "replace it with",
-            "expect".into(),
-            Applicability::MachineApplicable,
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", |diag| {
+            diag.span_suggestion(
+                ident.span,
+                "replace it with",
+                "expect",
+                Applicability::MachineApplicable,
+            );
+        });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
index 4b42616a636..4ab97118df1 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
@@ -1,5 +1,5 @@
 use super::{Attribute, ALLOW_ATTRIBUTES_WITHOUT_REASON};
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_lint::{LateContext, LintContext};
@@ -21,12 +21,14 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet
         return;
     }
 
-    span_lint_and_help(
+    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+    span_lint_and_then(
         cx,
         ALLOW_ATTRIBUTES_WITHOUT_REASON,
         attr.span,
         format!("`{}` attribute without specifying a reason", name.as_str()),
-        None,
-        "try adding a reason at the end with `, reason = \"..\"`",
+        |diag| {
+            diag.help("try adding a reason at the end with `, reason = \"..\"`");
+        },
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index 561ca9bd986..612712d1684 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{in_constant, is_else_clause};
+use clippy_utils::{is_else_clause, is_in_const_context};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
             && let Some(else_lit) = as_int_bool_lit(else_)
             && then_lit != else_lit
             && !expr.span.from_expansion()
-            && !in_constant(cx, expr.hir_id)
+            && !is_in_const_context(cx)
         {
             let ty = cx.typeck_results().expr_ty(then);
             let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index a1c6c0b608f..a2f48c18170 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -477,14 +477,12 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
             cx: self.cx,
         };
         if let Ok(expr) = h2q.run(e) {
-            if h2q.terminals.len() > 8 {
-                // QMC has exponentially slow behavior as the number of terminals increases
-                // 8 is reasonable, it takes approximately 0.2 seconds.
-                // See #825
+            let stats = terminal_stats(&expr);
+            if stats.ops > 7 {
+                // QMC has exponentially slow behavior as the number of ops increases.
+                // See #825, #13206
                 return;
             }
-
-            let stats = terminal_stats(&expr);
             let mut simplified = expr.simplify();
             for simple in Bool::Not(Box::new(expr)).simplify() {
                 match simple {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index ff460a3fd8e..bd3acc06f4b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_constant;
+use clippy_utils::is_in_const_context;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_isize_or_usize;
@@ -21,7 +21,7 @@ pub(super) fn check(
     cast_to_hir: &rustc_hir::Ty<'_>,
     msrv: &Msrv,
 ) {
-    if !should_lint(cx, expr, cast_from, cast_to, msrv) {
+    if !should_lint(cx, cast_from, cast_to, msrv) {
         return;
     }
 
@@ -70,9 +70,9 @@ pub(super) fn check(
     );
 }
 
-fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
+fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
-    if in_constant(cx, expr.hir_id) {
+    if is_in_const_context(cx) {
         return false;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
index 5bc8692c289..464eabe5d9a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
@@ -1,6 +1,6 @@
 use super::CAST_NAN_TO_INT;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_note;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
 }
 
 fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    match constant(cx, cx.typeck_results(), e) {
+    match ConstEvalCtxt::new(cx).eval(e) {
         // FIXME(f16_f128): add these types when nan checks are available on all platforms
         Some(Constant::F64(n)) => n.is_nan(),
         Some(Constant::F32(n)) => n.is_nan(),
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 7c5acd1a678..102fe25fc67 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::expr_or_init;
 use clippy_utils::source::snippet;
@@ -15,7 +15,7 @@ use rustc_target::abi::IntegerType;
 use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
 
 fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
-    if let Some(Constant::Int(c)) = constant(cx, cx.typeck_results(), expr) {
+    if let Some(Constant::Int(c)) = ConstEvalCtxt::new(cx).eval(expr) {
         Some(c)
     } else {
         None
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 8bbd41b0db1..9daf237344a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -1,7 +1,7 @@
 use std::convert::Infallible;
 use std::ops::ControlFlow;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::visitors::{for_each_expr_without_closures, Descend};
 use clippy_utils::{method_chain_args, sext};
@@ -88,7 +88,7 @@ fn get_const_signed_int_eval<'cx>(
 ) -> Option<i128> {
     let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr));
 
-    if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
+    if let Constant::Int(n) = ConstEvalCtxt::new(cx).eval(expr)?
         && let ty::Int(ity) = *ty.kind()
     {
         return Some(sext(cx.tcx, n, ity));
@@ -103,7 +103,7 @@ fn get_const_unsigned_int_eval<'cx>(
 ) -> Option<u128> {
     let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr));
 
-    if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
+    if let Constant::Int(n) = ConstEvalCtxt::new(cx).eval(expr)?
         && let ty::Uint(_ity) = *ty.kind()
     {
         return Some(n);
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
index 826589bf303..75de53f73ee 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
@@ -1,6 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
@@ -14,21 +14,24 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
         _ => { /* continue to checks */ },
     }
 
-    match cast_from.kind() {
-        ty::FnDef(..) | ty::FnPtr(_) => {
-            let mut applicability = Applicability::MaybeIncorrect;
-            let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+    if let ty::FnDef(..) | ty::FnPtr(_) = cast_from.kind() {
+        let mut applicability = Applicability::MaybeIncorrect;
+        let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
 
-            span_lint_and_sugg(
-                cx,
-                FN_TO_NUMERIC_CAST_ANY,
-                expr.span,
-                format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
-                "did you mean to invoke the function?",
-                format!("{from_snippet}() as {cast_to}"),
-                applicability,
-            );
-        },
-        _ => {},
+        span_lint_and_then(
+            cx,
+            FN_TO_NUMERIC_CAST_ANY,
+            expr.span,
+            format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
+            |diag| {
+                diag.span_suggestion_with_style(
+                    expr.span,
+                    "did you mean to invoke the function?",
+                    format!("{from_snippet}() as {cast_to}"),
+                    applicability,
+                    SuggestionStyle::ShowAlways,
+                );
+            },
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
index 5071af5ecb9..3c1c7d2dc3a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::{in_constant, is_integer_literal, std_or_core};
+use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
@@ -10,7 +10,7 @@ use super::ZERO_PTR;
 pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>) {
     if let TyKind::Ptr(ref mut_ty) = to.kind
         && is_integer_literal(from, 0)
-        && !in_constant(cx, from.hir_id)
+        && !is_in_const_context(cx)
         && let Some(std_or_core) = std_or_core(cx)
     {
         let (msg, sugg_fn) = match mut_ty.mutbl {
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 0b1ab5411bf..1711565fca8 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -4,7 +4,7 @@ use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
+use clippy_utils::{is_in_const_context, is_integer_literal, SpanlessEq};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
                 _ => return,
             }
             && !in_external_macro(cx.sess(), item.span)
-            && !in_constant(cx, item.hir_id)
+            && !is_in_const_context(cx)
             && self.msrv.meets(msrvs::TRY_FROM)
             && let Some(cv) = match op2 {
                 // todo: check for case signed -> larger unsigned == only x >= 0
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 2c23c0b4f15..5d78744e9b5 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq};
+use clippy_utils::{if_sequence, is_else_clause, is_in_const_context, SpanlessEq};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
             return;
         }
 
-        if in_constant(cx, expr.hir_id) {
+        if is_in_const_context(cx) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index 27c00948a8f..b49a977dbea 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -1,6 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use rustc_errors::Applicability;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -39,14 +39,24 @@ impl LateLintPass<'_> for CreateDir {
             && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id)
         {
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 CREATE_DIR,
                 expr.span,
                 "calling `std::fs::create_dir` where there may be a better way",
-                "consider calling `std::fs::create_dir_all` instead",
-                format!("create_dir_all({})", snippet(cx, arg.span, "..")),
-                Applicability::MaybeIncorrect,
+                |diag| {
+                    let mut app = Applicability::MaybeIncorrect;
+                    diag.span_suggestion_with_style(
+                        expr.span,
+                        "consider calling `std::fs::create_dir_all` instead",
+                        format!(
+                            "create_dir_all({})",
+                            snippet_with_applicability(cx, arg.span, "..", &mut app)
+                        ),
+                        app,
+                        SuggestionStyle::ShowAlways,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index 788c6f3ada2..93c8fff05e9 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_in_test;
 use clippy_utils::macros::{macro_backtrace, MacroCall};
 use clippy_utils::source::snippet_with_applicability;
@@ -65,61 +65,67 @@ impl LateLintPass<'_> for DbgMacro {
             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
             !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))
         {
-            let mut applicability = Applicability::MachineApplicable;
-
-            let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
-                // dbg!()
-                ExprKind::Block(..) => {
-                    // If the `dbg!` macro is a "free" statement and not contained within other expressions,
-                    // remove the whole statement.
-                    if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
-                        && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
-                    {
-                        (macro_call.span.to(semi_span), String::new())
-                    } else {
-                        (macro_call.span, String::from("()"))
-                    }
-                },
-                // dbg!(1)
-                ExprKind::Match(val, ..) => (
-                    macro_call.span,
-                    snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string(),
-                ),
-                // dbg!(2, 3)
-                ExprKind::Tup(
-                    [
-                        Expr {
-                            kind: ExprKind::Match(first, ..),
-                            ..
-                        },
-                        ..,
-                        Expr {
-                            kind: ExprKind::Match(last, ..),
-                            ..
-                        },
-                    ],
-                ) => {
-                    let snippet = snippet_with_applicability(
-                        cx,
-                        first.span.source_callsite().to(last.span.source_callsite()),
-                        "..",
-                        &mut applicability,
-                    );
-                    (macro_call.span, format!("({snippet})"))
-                },
-                _ => return,
-            };
-
             self.prev_ctxt = cur_syntax_ctxt;
 
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 DBG_MACRO,
-                sugg_span,
+                macro_call.span,
                 "the `dbg!` macro is intended as a debugging tool",
-                "remove the invocation before committing it to a version control system",
-                suggestion,
-                applicability,
+                |diag| {
+                    let mut applicability = Applicability::MachineApplicable;
+
+                    let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
+                        // dbg!()
+                        ExprKind::Block(..) => {
+                            // If the `dbg!` macro is a "free" statement and not contained within other expressions,
+                            // remove the whole statement.
+                            if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
+                                && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
+                            {
+                                (macro_call.span.to(semi_span), String::new())
+                            } else {
+                                (macro_call.span, String::from("()"))
+                            }
+                        },
+                        // dbg!(1)
+                        ExprKind::Match(val, ..) => (
+                            macro_call.span,
+                            snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
+                                .to_string(),
+                        ),
+                        // dbg!(2, 3)
+                        ExprKind::Tup(
+                            [
+                                Expr {
+                                    kind: ExprKind::Match(first, ..),
+                                    ..
+                                },
+                                ..,
+                                Expr {
+                                    kind: ExprKind::Match(last, ..),
+                                    ..
+                                },
+                            ],
+                        ) => {
+                            let snippet = snippet_with_applicability(
+                                cx,
+                                first.span.source_callsite().to(last.span.source_callsite()),
+                                "..",
+                                &mut applicability,
+                            );
+                            (macro_call.span, format!("({snippet})"))
+                        },
+                        _ => unreachable!(),
+                    };
+
+                    diag.span_suggestion(
+                        sugg_span,
+                        "remove the invocation before committing it to a version control system",
+                        suggestion,
+                        applicability,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 69f9eb6842b..3fb083dd833 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -14,8 +14,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO,
     #[cfg(feature = "internal")]
-    crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON_INFO,
-    #[cfg(feature = "internal")]
     crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO,
@@ -741,6 +739,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::unused_async::UNUSED_ASYNC_INFO,
     crate::unused_io_amount::UNUSED_IO_AMOUNT_INFO,
     crate::unused_peekable::UNUSED_PEEKABLE_INFO,
+    crate::unused_result_ok::UNUSED_RESULT_OK_INFO,
     crate::unused_rounding::UNUSED_ROUNDING_INFO,
     crate::unused_self::UNUSED_SELF_INFO,
     crate::unused_unit::UNUSED_UNIT_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 72fa05be3cc..0b7279f2b36 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -221,7 +221,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                         .map(ToString::to_string)
                         .collect::<Vec<_>>()
                         .join(", ");
-                    format!("{adt_def_ty_name}::<{}>", &tys_str)
+                    format!("{adt_def_ty_name}::<{tys_str}>")
                 } else {
                     binding_type.to_string()
                 };
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 9af73db6849..a74b3a8c836 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -92,20 +92,8 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
             let (suffix, is_float) = match lit_ty.kind() {
                 ty::Int(IntTy::I32) => ("i32", false),
                 ty::Float(FloatTy::F64) => ("f64", true),
-                // Default numeric fallback never results in other types.
                 _ => return,
             };
-
-            let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
-                src
-            } else {
-                match lit.node {
-                    LitKind::Int(src, _) => format!("{src}"),
-                    LitKind::Float(src, _) => format!("{src}"),
-                    _ => return,
-                }
-            };
-            let sugg = numeric_literal::format(&src, Some(suffix), is_float);
             span_lint_hir_and_then(
                 self.cx,
                 DEFAULT_NUMERIC_FALLBACK,
@@ -113,6 +101,17 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
                 lit.span,
                 "default numeric fallback might occur",
                 |diag| {
+                    let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
+                        src
+                    } else {
+                        match lit.node {
+                            LitKind::Int(src, _) => format!("{src}"),
+                            LitKind::Float(src, _) => format!("{src}"),
+                            _ => unreachable!("Default numeric fallback never results in other types"),
+                        }
+                    };
+
+                    let sugg = numeric_literal::format(&src, Some(suffix), is_float);
                     diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect);
                 },
             );
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 3fa9bad0d03..9f020d3081c 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
@@ -56,16 +56,18 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation {
             && is_union_with_two_non_zst_fields(cx, item)
             && !has_c_repr_attr(cx, item.hir_id())
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 DEFAULT_UNION_REPRESENTATION,
                 item.span,
                 "this union has the default representation",
-                None,
-                format!(
-                    "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
-                    cx.tcx.def_path_str(item.owner_id)
-                ),
+                |diag| {
+                    diag.help(format!(
+                        "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
+                        cx.tcx.def_path_str(item.owner_id)
+                    ));
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index a0900f46f6a..0066ed64325 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -1,243 +1,181 @@
-// NOTE: Entries should be created with `cargo dev deprecate`
-
-/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
-/// enables the simple extraction of the metadata without changing the current deprecation
-/// declaration.
-pub struct ClippyDeprecatedLint {
-    #[allow(dead_code)]
-    pub desc: &'static str,
-}
-
-#[macro_export]
-macro_rules! declare_deprecated_lint {
-    { $(#[$attr:meta])* pub $name: ident, $reason: literal} => {
-        $(#[$attr])*
-        #[allow(dead_code)]
-        pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint {
-            desc: $reason
-        };
-    }
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This used to check for `assert!(a == b)` and recommend
-    /// replacement with `assert_eq!(a, b)`, but this is no longer needed after RFC 2011.
+// This file is managed by `cargo dev rename_lint` and `cargo dev deprecate_lint`.
+// Prefer to use those when possible.
+
+macro_rules! declare_with_version {
+    ($name:ident($name_version:ident): &[$ty:ty] = &[$(
+        #[clippy::version = $version:literal]
+        $e:expr,
+    )*]) => {
+        pub static $name: &[$ty] = &[$($e),*];
+        #[allow(unused)]
+        pub static $name_version: &[&str] = &[$($version),*];
+    };
+}
+
+#[rustfmt::skip]
+declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[
     #[clippy::version = "pre 1.29.0"]
-    pub SHOULD_ASSERT_EQ,
-    "`assert!()` will be more flexible with RFC 2011"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This used to check for `Vec::extend`, which was slower than
-    /// `Vec::extend_from_slice`. Thanks to specialization, this is no longer true.
+    ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"),
     #[clippy::version = "pre 1.29.0"]
-    pub EXTEND_FROM_SLICE,
-    "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// `Range::step_by(0)` used to be linted since it's
-    /// an infinite iterator, which is better expressed by `iter::repeat`,
-    /// but the method has been removed for `Iterator::step_by` which panics
-    /// if given a zero
+    ("clippy::extend_from_slice", "`Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization"),
     #[clippy::version = "pre 1.29.0"]
-    pub RANGE_STEP_BY_ZERO,
-    "`iterator.step_by(0)` panics nowadays"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This used to check for `Vec::as_slice`, which was unstable with good
-    /// stable alternatives. `Vec::as_slice` has now been stabilized.
+    ("clippy::range_step_by_zero", "`Iterator::step_by(0)` now panics and is no longer an infinite iterator"),
     #[clippy::version = "pre 1.29.0"]
-    pub UNSTABLE_AS_SLICE,
-    "`Vec::as_slice` has been stabilized in 1.7"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This used to check for `Vec::as_mut_slice`, which was unstable with good
-    /// stable alternatives. `Vec::as_mut_slice` has now been stabilized.
+    ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"),
     #[clippy::version = "pre 1.29.0"]
-    pub UNSTABLE_AS_MUT_SLICE,
-    "`Vec::as_mut_slice` has been stabilized in 1.7"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint should never have applied to non-pointer types, as transmuting
-    /// between non-pointer types of differing alignment is well-defined behavior (it's semantically
-    /// equivalent to a memcpy). This lint has thus been refactored into two separate lints:
-    /// cast_ptr_alignment and transmute_ptr_to_ptr.
+    ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"),
     #[clippy::version = "pre 1.29.0"]
-    pub MISALIGNED_TRANSMUTE,
-    "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint is too subjective, not having a good reason for being in clippy.
-    /// Additionally, compound assignment operators may be overloaded separately from their non-assigning
-    /// counterparts, so this lint may suggest a change in behavior or the code may not compile.
+    ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"),
     #[clippy::version = "1.30.0"]
-    pub ASSIGN_OPS,
-    "using compound assignment operators (e.g., `+=`) is harmless"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// The original rule will only lint for `if let`. After
-    /// making it support to lint `match`, naming as `if let` is not suitable for it.
-    /// So, this lint is deprecated.
+    ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"),
     #[clippy::version = "pre 1.29.0"]
-    pub IF_LET_REDUNDANT_PATTERN_MATCHING,
-    "this lint has been changed to redundant_pattern_matching"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint used to suggest replacing `let mut vec =
-    /// Vec::with_capacity(n); vec.set_len(n);` with `let vec = vec![0; n];`. The
-    /// replacement has very different performance characteristics so the lint is
-    /// deprecated.
-    #[clippy::version = "pre 1.29.0"]
-    pub UNSAFE_VECTOR_INITIALIZATION,
-    "the replacement suggested by this lint had substantially different behavior"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been superseded by #[must_use] in rustc.
+    ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"),
     #[clippy::version = "1.39.0"]
-    pub UNUSED_COLLECT,
-    "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// Associated-constants are now preferred.
+    ("clippy::unused_collect", "`Iterator::collect` is now marked as `#[must_use]`"),
     #[clippy::version = "1.44.0"]
-    pub REPLACE_CONSTS,
-    "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// The regex! macro does not exist anymore.
+    ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"),
     #[clippy::version = "1.47.0"]
-    pub REGEX_MACRO,
-    "the regex! macro has been removed from the regex crate in 2018"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been replaced by `manual_find_map`, a
-    /// more specific lint.
-    #[clippy::version = "1.51.0"]
-    pub FIND_MAP,
-    "this lint has been replaced by `manual_find_map`, a more specific lint"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been replaced by `manual_filter_map`, a
-    /// more specific lint.
-    #[clippy::version = "1.53.0"]
-    pub FILTER_MAP,
-    "this lint has been replaced by `manual_filter_map`, a more specific lint"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// The `avoid_breaking_exported_api` config option was added, which
-    /// enables the `enum_variant_names` lint for public items.
+    ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"),
     #[clippy::version = "1.54.0"]
-    pub PUB_ENUM_VARIANT_NAMES,
-    "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// The `avoid_breaking_exported_api` config option was added, which
-    /// enables the `wrong_self_conversion` lint for public items.
+    ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"),
     #[clippy::version = "1.54.0"]
-    pub WRONG_PUB_SELF_CONVENTION,
-    "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been superseded by rustc's own [`unexpected_cfgs`] lint that is able to detect the `#[cfg(features)]` and `#[cfg(tests)]` typos.
-    ///
-    /// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs
+    ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"),
+    // end deprecated lints. used by `cargo dev deprecate_lint`
+]}
+
+#[rustfmt::skip]
+declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
+    #[clippy::version = ""]
+    ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
+    #[clippy::version = ""]
+    ("clippy::blacklisted_name", "clippy::disallowed_names"),
+    #[clippy::version = ""]
+    ("clippy::block_in_if_condition_expr", "clippy::blocks_in_conditions"),
+    #[clippy::version = ""]
+    ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_conditions"),
+    #[clippy::version = ""]
+    ("clippy::blocks_in_if_conditions", "clippy::blocks_in_conditions"),
+    #[clippy::version = ""]
+    ("clippy::box_vec", "clippy::box_collection"),
+    #[clippy::version = ""]
+    ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
+    #[clippy::version = ""]
+    ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
+    #[clippy::version = ""]
+    ("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"),
+    #[clippy::version = ""]
+    ("clippy::disallowed_method", "clippy::disallowed_methods"),
+    #[clippy::version = ""]
+    ("clippy::disallowed_type", "clippy::disallowed_types"),
+    #[clippy::version = ""]
+    ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
+    #[clippy::version = "1.51.0"]
+    ("clippy::find_map", "clippy::manual_find_map"),
+    #[clippy::version = "1.53.0"]
+    ("clippy::filter_map", "clippy::manual_filter_map"),
+    #[clippy::version = ""]
+    ("clippy::identity_conversion", "clippy::useless_conversion"),
+    #[clippy::version = "pre 1.29.0"]
+    ("clippy::if_let_redundant_pattern_matching", "clippy::redundant_pattern_matching"),
+    #[clippy::version = ""]
+    ("clippy::if_let_some_result", "clippy::match_result_ok"),
+    #[clippy::version = ""]
+    ("clippy::incorrect_clone_impl_on_copy_type", "clippy::non_canonical_clone_impl"),
+    #[clippy::version = ""]
+    ("clippy::incorrect_partial_ord_impl_on_ord_type", "clippy::non_canonical_partial_ord_impl"),
+    #[clippy::version = ""]
+    ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"),
+    #[clippy::version = ""]
+    ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
+    #[clippy::version = ""]
+    ("clippy::new_without_default_derive", "clippy::new_without_default"),
+    #[clippy::version = ""]
+    ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
+    #[clippy::version = ""]
+    ("clippy::option_expect_used", "clippy::expect_used"),
+    #[clippy::version = ""]
+    ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
+    #[clippy::version = ""]
+    ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
+    #[clippy::version = ""]
+    ("clippy::option_unwrap_used", "clippy::unwrap_used"),
+    #[clippy::version = ""]
+    ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"),
+    #[clippy::version = ""]
+    ("clippy::ref_in_deref", "clippy::needless_borrow"),
+    #[clippy::version = ""]
+    ("clippy::result_expect_used", "clippy::expect_used"),
+    #[clippy::version = ""]
+    ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
+    #[clippy::version = ""]
+    ("clippy::result_unwrap_used", "clippy::unwrap_used"),
+    #[clippy::version = ""]
+    ("clippy::single_char_push_str", "clippy::single_char_add_str"),
+    #[clippy::version = ""]
+    ("clippy::stutter", "clippy::module_name_repetitions"),
+    #[clippy::version = ""]
+    ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"),
+    #[clippy::version = ""]
+    ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
+    #[clippy::version = ""]
+    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
+    #[clippy::version = ""]
+    ("clippy::zero_width_space", "clippy::invisible_characters"),
+    #[clippy::version = ""]
+    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
+    #[clippy::version = ""]
+    ("clippy::clone_double_ref", "suspicious_double_ref_op"),
+    #[clippy::version = ""]
+    ("clippy::cmp_nan", "invalid_nan_comparisons"),
+    #[clippy::version = ""]
+    ("clippy::drop_bounds", "drop_bounds"),
+    #[clippy::version = ""]
+    ("clippy::drop_copy", "dropping_copy_types"),
+    #[clippy::version = ""]
+    ("clippy::drop_ref", "dropping_references"),
+    #[clippy::version = ""]
+    ("clippy::fn_null_check", "useless_ptr_null_checks"),
+    #[clippy::version = ""]
+    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::forget_copy", "forgetting_copy_types"),
+    #[clippy::version = ""]
+    ("clippy::forget_ref", "forgetting_references"),
+    #[clippy::version = ""]
+    ("clippy::into_iter_on_array", "array_into_iter"),
+    #[clippy::version = ""]
+    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
+    #[clippy::version = ""]
+    ("clippy::invalid_ref", "invalid_value"),
+    #[clippy::version = ""]
+    ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"),
+    #[clippy::version = ""]
+    ("clippy::let_underscore_drop", "let_underscore_drop"),
     #[clippy::version = "1.80.0"]
-    pub MAYBE_MISUSED_CFG,
-    "this lint has been replaced by `unexpected_cfgs`"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been superseded by rustc's own [`unexpected_cfgs`] lint that is able to detect invalid `#[cfg(linux)]` attributes.
-    ///
-    /// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs
+    ("clippy::maybe_misused_cfg", "unexpected_cfgs"),
+    #[clippy::version = ""]
+    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
     #[clippy::version = "1.80.0"]
-    pub MISMATCHED_TARGET_OS,
-    "this lint has been replaced by `unexpected_cfgs`"
-}
+    ("clippy::mismatched_target_os", "unexpected_cfgs"),
+    #[clippy::version = ""]
+    ("clippy::panic_params", "non_fmt_panics"),
+    #[clippy::version = ""]
+    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
+    #[clippy::version = ""]
+    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
+    #[clippy::version = ""]
+    ("clippy::undropped_manually_drops", "undropped_manually_drops"),
+    #[clippy::version = ""]
+    ("clippy::unknown_clippy_lints", "unknown_lints"),
+    #[clippy::version = ""]
+    ("clippy::unused_label", "unused_labels"),
+    #[clippy::version = ""]
+    ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
+    #[clippy::version = ""]
+    ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
+    // end renamed lints. used by `cargo dev rename_lint`
+]}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 253f9959e13..d0cb2488468 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs};
+use clippy_utils::ty::{implements_trait, is_manually_drop};
 use clippy_utils::{
     expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy,
     ExprUseNode,
@@ -947,7 +947,7 @@ fn report<'tcx>(
             let (expr_str, _expr_is_macro_call) =
                 snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
             let ty = typeck.expr_ty(expr);
-            let (_, ref_count) = peel_mid_ty_refs(ty);
+            let (_, ref_count) = peel_middle_ty_refs(ty);
             let deref_str = if ty_changed_count >= ref_count && ref_count != 0 {
                 // a deref call changing &T -> &U requires two deref operators the first time
                 // this occurs. One to remove the reference, a second to call the deref impl.
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 5b6a5b08aa9..d7b3a7c74f3 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -5,7 +5,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::Visitable;
-use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args};
+use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args};
 use pulldown_cmark::Event::{
     Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start,
     TaskListMarker, Text,
@@ -768,7 +768,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     );
                 }
             },
-            FootnoteReference(text) | Text(text) => {
+            Text(text) => {
                 paragraph_range.end = range.end;
                 let range_ = range.clone();
                 ticks_unbalanced |= text.contains('`')
@@ -812,7 +812,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     }
                     text_to_check.push((text, range, code_level));
                 }
-            },
+            }
+            FootnoteReference(_) => {}
         }
     }
     headers
@@ -857,7 +858,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
                     "assert" | "assert_eq" | "assert_ne"
                 )
             {
-                self.is_const = in_constant(self.cx, expr.hir_id);
+                self.is_const = self.cx.tcx.hir().is_inside_const_context(expr.hir_id);
                 self.panic_span = Some(macro_call.span);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 4a6ffcd9a78..c7dd7292a14 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_must_use_func_call;
 use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
 use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
@@ -126,14 +126,14 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
                 },
                 _ => return,
             };
-            span_lint_and_note(
-                cx,
-                lint,
-                expr.span,
-                msg,
-                note_span,
-                format!("argument has type `{arg_ty}`"),
-            );
+            span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+                let note = format!("argument has type `{arg_ty}`");
+                if let Some(span) = note_span {
+                    diag.span_note(span, note);
+                } else {
+                    diag.note(note);
+                }
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
index 7a6dc469727..02f9c2c3648 100644
--- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
+++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
@@ -1,6 +1,6 @@
 //! Lint on if expressions with an else if, but without a final else branch.
 
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -54,13 +54,15 @@ impl EarlyLintPass for ElseIfWithoutElse {
             && let ExprKind::If(_, _, None) = els.kind
             && !in_external_macro(cx.sess(), item.span)
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 ELSE_IF_WITHOUT_ELSE,
                 els.span,
                 "`if` expression with an `else if`, but without a final `else`",
-                None,
-                "add an `else` block here",
+                |diag| {
+                    diag.help("add an `else` block here");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs
index c5fc72b5e2d..b66dd2108fc 100644
--- a/src/tools/clippy/clippy_lints/src/empty_drop.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::peel_blocks;
 use rustc_errors::Applicability;
 use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node};
@@ -50,15 +50,14 @@ impl LateLintPass<'_> for EmptyDrop {
             && block.stmts.is_empty()
             && block.expr.is_none()
         {
-            span_lint_and_sugg(
-                cx,
-                EMPTY_DROP,
-                item.span,
-                "empty drop implementation",
-                "try removing this impl",
-                String::new(),
-                Applicability::MaybeIncorrect,
-            );
+            span_lint_and_then(cx, EMPTY_DROP, item.span, "empty drop implementation", |diag| {
+                diag.span_suggestion_hidden(
+                    item.span,
+                    "try removing this impl",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index 5bba9c562b9..209104c5385 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -7,7 +7,6 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Symbol;
-use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -141,52 +140,6 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
         _ => return,
     };
 
-    let mut help = None;
-
-    'build_help: {
-        // all lints disallowed, don't give help here
-        if [&[lint], other_lints.as_slice()]
-            .concat()
-            .iter()
-            .all(|lint| !lint.allowed(cx, expr))
-        {
-            break 'build_help;
-        }
-
-        // ne_bytes and all other lints allowed
-        if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) {
-            help = Some(Cow::Borrowed("specify the desired endianness explicitly"));
-            break 'build_help;
-        }
-
-        // le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but
-        // le_bytes is not
-        if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) {
-            help = Some(Cow::Borrowed("use the native endianness instead"));
-            break 'build_help;
-        }
-
-        let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr));
-        let len = allowed_lints.clone().count();
-
-        let mut help_str = "use ".to_owned();
-
-        for (i, lint) in allowed_lints.enumerate() {
-            let only_one = len == 1;
-            if !only_one {
-                help_str.push_str("either of ");
-            }
-
-            help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
-
-            if i != len && !only_one {
-                help_str.push_str("or ");
-            }
-        }
-
-        help = Some(Cow::Owned(help_str + "instead"));
-    }
-
     span_lint_and_then(
         cx,
         lint.as_lint(),
@@ -198,9 +151,47 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
             if prefix == Prefix::To { " method" } else { "" },
         ),
         move |diag| {
-            if let Some(help) = help {
-                diag.help(help);
+            // all lints disallowed, don't give help here
+            if [&[lint], other_lints.as_slice()]
+                .concat()
+                .iter()
+                .all(|lint| !lint.allowed(cx, expr))
+            {
+                return;
+            }
+
+            // ne_bytes and all other lints allowed
+            if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) {
+                diag.help("specify the desired endianness explicitly");
+                return;
+            }
+
+            // le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but
+            // le_bytes is not
+            if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) {
+                diag.help("use the native endianness instead");
+                return;
+            }
+
+            let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr));
+            let len = allowed_lints.clone().count();
+
+            let mut help_str = "use ".to_owned();
+
+            for (i, lint) in allowed_lints.enumerate() {
+                let only_one = len == 1;
+                if !only_one {
+                    help_str.push_str("either of ");
+                }
+
+                help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
+
+                if i != len && !only_one {
+                    help_str.push_str("or ");
+                }
             }
+            help_str.push_str("instead");
+            diag.help(help_str);
         },
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 30eb643c42e..e54cd248ead 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
                         .const_eval_poly(def_id.to_def_id())
                         .ok()
                         .map(|val| rustc_middle::mir::Const::from_value(val, ty));
-                    if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) {
+                    if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx.tcx, c)) {
                         if let ty::Adt(adt, _) = ty.kind() {
                             if adt.is_enum() {
                                 ty = adt.repr().discr_type().to_ty(cx.tcx);
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 0ed7859418b..5a7226d590c 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -9,8 +9,7 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, TyCtxt,
-    TypeVisitableExt, TypeckResults,
+    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -74,159 +73,184 @@ declare_clippy_lint! {
 declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
 
 impl<'tcx> LateLintPass<'tcx> for EtaReduction {
-    #[allow(clippy::too_many_lines)]
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let body = if let ExprKind::Closure(c) = expr.kind
-            && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
-            && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
-            && !expr.span.from_expansion()
-        {
-            cx.tcx.hir().body(c.body)
-        } else {
-            return;
-        };
-
-        if body.value.span.from_expansion() {
-            if body.params.is_empty() {
-                if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) {
-                    // replace `|| vec![]` with `Vec::new`
-                    span_lint_and_sugg(
-                        cx,
-                        REDUNDANT_CLOSURE,
-                        expr.span,
-                        "redundant closure",
-                        "replace the closure with `Vec::new`",
-                        "std::vec::Vec::new".into(),
-                        Applicability::MachineApplicable,
-                    );
-                }
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if let ExprKind::MethodCall(_method, receiver, args, _) = expr.kind {
+            for arg in args {
+                check_clousure(cx, Some(receiver), arg);
             }
-            // skip `foo(|| macro!())`
-            return;
         }
+        if let ExprKind::Call(func, args) = expr.kind {
+            check_clousure(cx, None, func);
+            for arg in args {
+                check_clousure(cx, None, arg);
+            }
+        }
+    }
+}
 
-        let typeck = cx.typeck_results();
-        let closure = if let ty::Closure(_, closure_subs) = typeck.expr_ty(expr).kind() {
-            closure_subs.as_closure()
-        } else {
-            return;
-        };
+#[allow(clippy::too_many_lines)]
+fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
+    let body = if let ExprKind::Closure(c) = expr.kind
+        && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
+        && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
+        && !expr.span.from_expansion()
+    {
+        cx.tcx.hir().body(c.body)
+    } else {
+        return;
+    };
 
-        if is_adjusted(cx, body.value) {
-            return;
+    if body.value.span.from_expansion() {
+        if body.params.is_empty() {
+            if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) {
+                // replace `|| vec![]` with `Vec::new`
+                span_lint_and_sugg(
+                    cx,
+                    REDUNDANT_CLOSURE,
+                    expr.span,
+                    "redundant closure",
+                    "replace the closure with `Vec::new`",
+                    "std::vec::Vec::new".into(),
+                    Applicability::MachineApplicable,
+                );
+            }
         }
+        // skip `foo(|| macro!())`
+        return;
+    }
 
-        match body.value.kind {
-            ExprKind::Call(callee, args)
-                if matches!(
-                    callee.kind,
-                    ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))
-                ) =>
+    if is_adjusted(cx, body.value) {
+        return;
+    }
+
+    let typeck = cx.typeck_results();
+    let closure = if let ty::Closure(_, closure_subs) = typeck.expr_ty(expr).kind() {
+        closure_subs.as_closure()
+    } else {
+        return;
+    };
+    let closure_sig = cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder();
+    match body.value.kind {
+        ExprKind::Call(callee, args)
+            if matches!(
+                callee.kind,
+                ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))
+            ) =>
+        {
+            let callee_ty_raw = typeck.expr_ty(callee);
+            let callee_ty = callee_ty_raw.peel_refs();
+            if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
+                || !check_inputs(typeck, body.params, None, args)
             {
-                let callee_ty_raw = typeck.expr_ty(callee);
-                let callee_ty = callee_ty_raw.peel_refs();
-                if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
-                    || !check_inputs(typeck, body.params, None, args)
-                {
-                    return;
-                }
-                let callee_ty_adjusted = typeck
-                    .expr_adjustments(callee)
-                    .last()
-                    .map_or(callee_ty, |a| a.target.peel_refs());
+                return;
+            }
+            let callee_ty_adjusted = typeck
+                .expr_adjustments(callee)
+                .last()
+                .map_or(callee_ty, |a| a.target.peel_refs());
 
-                let sig = match callee_ty_adjusted.kind() {
-                    ty::FnDef(def, _) => {
-                        // Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
-                        if cx.tcx.has_attr(*def, sym::track_caller) {
-                            return;
-                        }
+            let sig = match callee_ty_adjusted.kind() {
+                ty::FnDef(def, _) => {
+                    // Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
+                    if cx.tcx.has_attr(*def, sym::track_caller) {
+                        return;
+                    }
 
-                        cx.tcx.fn_sig(def).skip_binder().skip_binder()
-                    },
-                    ty::FnPtr(sig) => sig.skip_binder(),
-                    ty::Closure(_, subs) => cx
-                        .tcx
-                        .signature_unclosure(subs.as_closure().sig(), Safety::Safe)
-                        .skip_binder(),
-                    _ => {
-                        if typeck.type_dependent_def_id(body.value.hir_id).is_some()
-                            && let subs = typeck.node_args(body.value.hir_id)
-                            && let output = typeck.expr_ty(body.value)
-                            && let ty::Tuple(tys) = *subs.type_at(1).kind()
-                        {
-                            cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, Abi::Rust)
-                        } else {
-                            return;
-                        }
-                    },
-                };
-                if check_sig(cx, closure, sig)
-                    && let generic_args = typeck.node_args(callee.hir_id)
-                    // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
-                    // `'static` unless `T: 'static`. The cast `T::f as fn()` will, however, result
-                    // in a type which is `'static`.
-                    // For now ignore all callee types which reference a type parameter.
-                    && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
-                {
-                    span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
-                        if let Some(mut snippet) = snippet_opt(cx, callee.span) {
-                            if path_to_local(callee).map_or(false, |l| {
-                                // FIXME: Do we really need this `local_used_in` check?
-                                // Isn't it checking something like... `callee(callee)`?
-                                // If somehow this check is needed, add some test for it,
-                                // 'cuz currently nothing changes after deleting this check.
-                                local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
-                            }) {
-                                match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait(
-                                    cx.param_env,
-                                    Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
-                                    ty::PredicatePolarity::Positive,
-                                ) {
-                                    // Mutable closure is used after current expr; we cannot consume it.
-                                    Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
-                                    Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
-                                        snippet = format!("&{snippet}");
-                                    },
-                                    _ => (),
-                                }
+                    cx.tcx.fn_sig(def).skip_binder().skip_binder()
+                },
+                ty::FnPtr(sig) => sig.skip_binder(),
+                ty::Closure(_, subs) => cx
+                    .tcx
+                    .signature_unclosure(subs.as_closure().sig(), Safety::Safe)
+                    .skip_binder(),
+                _ => {
+                    if typeck.type_dependent_def_id(body.value.hir_id).is_some()
+                        && let subs = typeck.node_args(body.value.hir_id)
+                        && let output = typeck.expr_ty(body.value)
+                        && let ty::Tuple(tys) = *subs.type_at(1).kind()
+                    {
+                        cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, Abi::Rust)
+                    } else {
+                        return;
+                    }
+                },
+            };
+            if let Some(outer) = outer_receiver
+                && ty_has_static(sig.output())
+                && let generic_args = typeck.node_args(outer.hir_id)
+                // HACK: Given a closure in `T.method(|| f())`, where `fn f() -> U where U: 'static`, `T.method(f)`
+                // will succeed iff `T: 'static`. But the region of `T` is always erased by `typeck.expr_ty()` when
+                // T is a generic type. For example, return type of `Option<String>::as_deref()` is a generic.
+                // So we have a hack like this.
+                && generic_args.len() > 0
+            {
+                return;
+            }
+            if check_sig(closure_sig, sig)
+                && let generic_args = typeck.node_args(callee.hir_id)
+                // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
+                // `'static` unless `T: 'static`. The cast `T::f as fn()` will, however, result
+                // in a type which is `'static`.
+                // For now ignore all callee types which reference a type parameter.
+                && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+            {
+                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
+                    if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+                        if path_to_local(callee).map_or(false, |l| {
+                            // FIXME: Do we really need this `local_used_in` check?
+                            // Isn't it checking something like... `callee(callee)`?
+                            // If somehow this check is needed, add some test for it,
+                            // 'cuz currently nothing changes after deleting this check.
+                            local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
+                        }) {
+                            match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait(
+                                cx.param_env,
+                                Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                                ty::PredicatePolarity::Positive,
+                            ) {
+                                // Mutable closure is used after current expr; we cannot consume it.
+                                Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
+                                Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
+                                    snippet = format!("&{snippet}");
+                                },
+                                _ => (),
                             }
-                            diag.span_suggestion(
-                                expr.span,
-                                "replace the closure with the function itself",
-                                snippet,
-                                Applicability::MachineApplicable,
-                            );
                         }
-                    });
-                }
-            },
-            ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
-                if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
-                    && !cx.tcx.has_attr(method_def_id, sym::track_caller)
-                    && check_sig(cx, closure, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
-                {
-                    span_lint_and_then(
-                        cx,
-                        REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
-                        expr.span,
-                        "redundant closure",
-                        |diag| {
-                            let args = typeck.node_args(body.value.hir_id);
-                            let caller = self_.hir_id.owner.def_id;
-                            let type_name = get_path_from_caller_to_method_type(cx.tcx, caller, method_def_id, args);
-                            diag.span_suggestion(
-                                expr.span,
-                                "replace the closure with the method itself",
-                                format!("{}::{}", type_name, path.ident.name),
-                                Applicability::MachineApplicable,
-                            );
-                        },
-                    );
-                }
-            },
-            _ => (),
-        }
+                        diag.span_suggestion(
+                            expr.span,
+                            "replace the closure with the function itself",
+                            snippet,
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                });
+            }
+        },
+        ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
+            if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
+                && !cx.tcx.has_attr(method_def_id, sym::track_caller)
+                && check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
+            {
+                span_lint_and_then(
+                    cx,
+                    REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+                    expr.span,
+                    "redundant closure",
+                    |diag| {
+                        let args = typeck.node_args(body.value.hir_id);
+                        let caller = self_.hir_id.owner.def_id;
+                        let type_name = get_path_from_caller_to_method_type(cx.tcx, caller, method_def_id, args);
+                        diag.span_suggestion(
+                            expr.span,
+                            "replace the closure with the method itself",
+                            format!("{}::{}", type_name, path.ident.name),
+                            Applicability::MachineApplicable,
+                        );
+                    },
+                );
+            }
+        },
+        _ => (),
     }
 }
 
@@ -251,12 +275,8 @@ fn check_inputs(
         })
 }
 
-fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<TyCtxt<'tcx>>, call_sig: FnSig<'_>) -> bool {
-    call_sig.safety == Safety::Safe
-        && !has_late_bound_to_non_late_bound_regions(
-            cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder(),
-            call_sig,
-        )
+fn check_sig<'tcx>(closure_sig: FnSig<'tcx>, call_sig: FnSig<'tcx>) -> bool {
+    call_sig.safety == Safety::Safe && !has_late_bound_to_non_late_bound_regions(closure_sig, call_sig)
 }
 
 /// This walks through both signatures and checks for any time a late-bound region is expected by an
@@ -265,7 +285,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<TyCtxt<'tcx>>, c
 /// This is needed because rustc is unable to late bind early-bound regions in a function signature.
 fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'_>) -> bool {
     fn check_region(from_region: Region<'_>, to_region: Region<'_>) -> bool {
-        matches!(from_region.kind(), RegionKind::ReBound(..)) && !matches!(to_region.kind(), RegionKind::ReBound(..))
+        from_region.is_bound() && !to_region.is_bound()
     }
 
     fn check_subs(from_subs: &[GenericArg<'_>], to_subs: &[GenericArg<'_>]) -> bool {
@@ -318,3 +338,8 @@ fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'
         .zip(to_sig.inputs_and_output)
         .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
 }
+
+fn ty_has_static(ty: Ty<'_>) -> bool {
+    ty.walk()
+        .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if re.is_static()))
+}
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 0f4176ec73b..9bf3baba4b5 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -88,11 +88,11 @@ impl LateLintPass<'_> for ExhaustiveItems {
             && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
             && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
         {
-            let suggestion_span = item.span.shrink_to_lo();
-            let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
             span_lint_and_then(cx, lint, item.span, msg, |diag| {
+                let suggestion_span = item.span.shrink_to_lo();
+                let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
                 let sugg = format!("#[non_exhaustive]\n{indent}");
-                diag.span_suggestion(
+                diag.span_suggestion_verbose(
                     suggestion_span,
                     "try adding #[non_exhaustive]",
                     sugg,
diff --git a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
index bb74e345703..95b8e882da7 100644
--- a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
+++ b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -62,13 +62,15 @@ impl EarlyLintPass for FieldScopedVisibilityModifiers {
                 // pub(self) is equivalent to not using pub at all, so we ignore it
                 continue;
             }
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 FIELD_SCOPED_VISIBILITY_MODIFIERS,
                 field.vis.span,
                 "scoped visibility modifier on a field",
-                None,
-                "consider making the field private and adding a scoped visibility method for it",
+                |diag| {
+                    diag.help("consider making the field private and adding a scoped visibility method for it");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 6adcd2235dc..f095c1add91 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -1,7 +1,7 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::numeric_literal;
 use rustc_ast::ast::{self, LitFloatType, LitKind};
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, FloatTy};
@@ -105,32 +105,43 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
             if is_whole && !sym_str.contains(['e', 'E']) {
                 // Normalize the literal by stripping the fractional portion
                 if sym_str.split('.').next().unwrap() != float_str {
-                    // If the type suffix is missing the suggestion would be
-                    // incorrectly interpreted as an integer so adding a `.0`
-                    // suffix to prevent that.
-                    if type_suffix.is_none() {
-                        float_str.push_str(".0");
-                    }
-
-                    span_lint_and_sugg(
+                    span_lint_and_then(
                         cx,
                         LOSSY_FLOAT_LITERAL,
                         expr.span,
                         "literal cannot be represented as the underlying type without loss of precision",
-                        "consider changing the type or replacing it with",
-                        numeric_literal::format(&float_str, type_suffix, true),
-                        Applicability::MachineApplicable,
+                        |diag| {
+                            // If the type suffix is missing the suggestion would be
+                            // incorrectly interpreted as an integer so adding a `.0`
+                            // suffix to prevent that.
+                            if type_suffix.is_none() {
+                                float_str.push_str(".0");
+                            }
+                            diag.span_suggestion_with_style(
+                                expr.span,
+                                "consider changing the type or replacing it with",
+                                numeric_literal::format(&float_str, type_suffix, true),
+                                Applicability::MachineApplicable,
+                                SuggestionStyle::ShowAlways,
+                            );
+                        },
                     );
                 }
             } else if digits > max as usize && float_str.len() < sym_str.len() {
-                span_lint_and_sugg(
+                span_lint_and_then(
                     cx,
                     EXCESSIVE_PRECISION,
                     expr.span,
                     "float has excessive precision",
-                    "consider changing the type or truncating it to",
-                    numeric_literal::format(&float_str, type_suffix, true),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion_with_style(
+                            expr.span,
+                            "consider changing the type or truncating it to",
+                            numeric_literal::format(&float_str, type_suffix, true),
+                            Applicability::MachineApplicable,
+                            SuggestionStyle::ShowAlways,
+                        );
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 68bdf88d0a7..bf4bcabfe89 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -1,9 +1,9 @@
 use clippy_utils::consts::Constant::{Int, F32, F64};
-use clippy_utils::consts::{constant, constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::{
-    eq_expr_value, get_parent_expr, higher, in_constant, is_inherent_method_call, is_no_std_crate, numeric_literal,
-    peel_blocks, sugg,
+    eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate,
+    numeric_literal, peel_blocks, sugg,
 };
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -112,7 +112,7 @@ declare_lint_pass!(FloatingPointArithmetic => [
 // Returns the specialized log method for a given base if base is constant
 // and is one of 2, 10 and e
 fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> {
-    if let Some(value) = constant(cx, cx.typeck_results(), base) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval(base) {
         if F32(2.0) == value || F64(2.0) == value {
             return Some("log2");
         } else if F32(10.0) == value || F64(10.0) == value {
@@ -182,10 +182,8 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
         rhs,
     ) = receiver.kind
     {
-        let recv = match (
-            constant(cx, cx.typeck_results(), lhs),
-            constant(cx, cx.typeck_results(), rhs),
-        ) {
+        let ecx = ConstEvalCtxt::new(cx);
+        let recv = match (ecx.eval(lhs), ecx.eval(rhs)) {
             (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs,
             (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs,
             _ => return,
@@ -230,7 +228,7 @@ fn get_integer_from_float_constant(value: &Constant<'_>) -> Option<i32> {
 
 fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
-    if let Some(value) = constant(cx, cx.typeck_results(), receiver) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver) {
         if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
             Some("exp")
         } else if F32(2.0) == value || F64(2.0) == value {
@@ -251,7 +249,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
     }
 
     // Check argument
-    if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) {
         let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
             (
                 SUBOPTIMAL_FLOPS,
@@ -291,7 +289,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
 }
 
 fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) {
         if value == Int(2) {
             if let Some(parent) = get_parent_expr(cx, expr) {
                 if let Some(grandparent) = get_parent_expr(cx, parent) {
@@ -397,8 +395,9 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
             ) = &add_rhs.kind
             && lmethod_name.as_str() == "powi"
             && rmethod_name.as_str() == "powi"
-            && let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1)
-            && let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1)
+            && let ecx = ConstEvalCtxt::new(cx)
+            && let Some(lvalue) = ecx.eval(largs_1)
+            && let Some(rvalue) = ecx.eval(rargs_1)
             && Int(2) == lvalue
             && Int(2) == rvalue
         {
@@ -438,7 +437,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
         rhs,
     ) = expr.kind
         && cx.typeck_results().expr_ty(lhs).is_floating_point()
-        && let Some(value) = constant(cx, cx.typeck_results(), rhs)
+        && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs)
         && (F32(1.0) == value || F64(1.0) == value)
         && let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind
         && cx.typeck_results().expr_ty(self_arg).is_floating_point()
@@ -552,7 +551,7 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
 
 /// Returns true iff expr is some zero literal
 fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    match constant_simple(cx, cx.typeck_results(), expr) {
+    match ConstEvalCtxt::new(cx).eval_simple(expr) {
         Some(Int(i)) => i == 0,
         Some(F32(f)) => f == 0.0,
         Some(F64(f)) => f == 0.0,
@@ -696,8 +695,9 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             mul_lhs,
             mul_rhs,
         ) = &div_lhs.kind
-        && let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs)
-        && let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs)
+        && let ecx = ConstEvalCtxt::new(cx)
+        && let Some(rvalue) = ecx.eval(div_rhs)
+        && let Some(lvalue) = ecx.eval(mul_rhs)
     {
         // TODO: also check for constant values near PI/180 or 180/PI
         if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue)
@@ -753,7 +753,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
 impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // All of these operations are currently not const and are in std.
-        if in_constant(cx, expr.hir_id) {
+        if is_in_const_context(cx) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index a75538dd329..d05c5a01f41 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{higher, match_def_path, paths};
 use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
@@ -81,13 +81,15 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
             _ => return,
         };
         if is_format(cx, arg) {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 FORMAT_PUSH_STRING,
                 expr.span,
                 "`format!(..)` appended to existing `String`",
-                None,
-                "consider using `write!` to avoid the extra allocation",
+                |diag| {
+                    diag.help("consider using `write!` to avoid the extra allocation");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 9acb72b2e37..6ab7bbc2dfc 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use clippy_utils::{in_constant, is_integer_literal};
+use clippy_utils::{is_in_const_context, is_integer_literal};
 use rustc_errors::Applicability;
 use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -62,8 +62,8 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
             && matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_))
 
             // do not lint in constant context, because the suggestion won't work.
-            // NB: keep this check until a new `const_trait_impl` is available and stablized.
-            && !in_constant(cx, exp.hir_id)
+            // NB: keep this check until a new `const_trait_impl` is available and stabilized.
+            && !is_in_const_context(cx)
         {
             let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
                 let ty = cx.typeck_results().expr_ty(expr);
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index b38cc7b36a1..1c52514a330 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{higher, SpanlessEq};
+use clippy_utils::{eq_expr_value, higher};
 use core::ops::ControlFlow;
 use rustc_errors::Diag;
 use rustc_hir::{Expr, ExprKind};
@@ -51,53 +51,45 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
             if_else: Some(if_else),
             ..
         }) = higher::IfLet::hir(cx, expr)
+            && let Some(op_mutex) = for_each_expr_without_closures(let_expr, |e| mutex_lock_call(cx, e, None))
+            && let Some(arm_mutex) =
+                for_each_expr_without_closures((if_then, if_else), |e| mutex_lock_call(cx, e, Some(op_mutex)))
         {
-            let is_mutex_lock = |e: &'tcx Expr<'tcx>| {
-                if let Some(mutex) = is_mutex_lock_call(cx, e) {
-                    ControlFlow::Break(mutex)
-                } else {
-                    ControlFlow::Continue(())
-                }
+            let diag = |diag: &mut Diag<'_, ()>| {
+                diag.span_label(
+                    op_mutex.span,
+                    "this Mutex will remain locked for the entire `if let`-block...",
+                );
+                diag.span_label(
+                    arm_mutex.span,
+                    "... and is tried to lock again here, which will always deadlock.",
+                );
+                diag.help("move the lock call outside of the `if let ...` expression");
             };
-
-            let op_mutex = for_each_expr_without_closures(let_expr, is_mutex_lock);
-            if let Some(op_mutex) = op_mutex {
-                let arm_mutex = for_each_expr_without_closures((if_then, if_else), is_mutex_lock);
-                if let Some(arm_mutex) = arm_mutex
-                    && SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)
-                {
-                    let diag = |diag: &mut Diag<'_, ()>| {
-                        diag.span_label(
-                            op_mutex.span,
-                            "this Mutex will remain locked for the entire `if let`-block...",
-                        );
-                        diag.span_label(
-                            arm_mutex.span,
-                            "... and is tried to lock again here, which will always deadlock.",
-                        );
-                        diag.help("move the lock call outside of the `if let ...` expression");
-                    };
-                    span_lint_and_then(
-                        cx,
-                        IF_LET_MUTEX,
-                        expr.span,
-                        "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock",
-                        diag,
-                    );
-                }
-            }
+            span_lint_and_then(
+                cx,
+                IF_LET_MUTEX,
+                expr.span,
+                "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock",
+                diag,
+            );
         }
     }
 }
 
-fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+fn mutex_lock_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    op_mutex: Option<&'tcx Expr<'_>>,
+) -> ControlFlow<&'tcx Expr<'tcx>> {
     if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
         && path.ident.as_str() == "lock"
         && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
         && is_type_diagnostic_item(cx, ty, sym::Mutex)
+        && op_mutex.map_or(true, |op| eq_expr_value(cx, self_arg, op))
     {
-        Some(self_arg)
+        ControlFlow::Break(self_arg)
     } else {
-        None
+        ControlFlow::Continue(())
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs
index 2f6daeeb90d..0ebd8d0c237 100644
--- a/src/tools/clippy/clippy_lints/src/if_not_else.rs
+++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs
@@ -1,7 +1,7 @@
 //! lint on if branches that could be swapped so no `!` operation is necessary
 //! on the condition
 
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_else_clause;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
@@ -49,7 +49,7 @@ declare_clippy_lint! {
 declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
 
 fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
-    if let Some(value) = constant_simple(cx, cx.typeck_results(), expr) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval_simple(expr) {
         return Constant::Int(0) == value;
     }
     false
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index 39ea16b05d1..0bca53c1536 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -1,10 +1,12 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{contains_return, higher, in_constant, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
+use clippy_utils::{
+    contains_return, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, path_res, peel_blocks,
+};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind};
@@ -76,37 +78,44 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
             && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
             && !is_else_clause(cx.tcx, expr)
-            && !in_constant(cx, expr.hir_id)
+            && !is_in_const_context(cx)
             && !in_external_macro(cx.sess(), expr.span)
             && self.msrv.meets(msrvs::BOOL_THEN)
             && !contains_return(then_block.stmts)
         {
-            let mut app = Applicability::Unspecified;
-            let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
-                .maybe_par()
-                .to_string();
-            let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
-            let mut method_body = if then_block.stmts.is_empty() {
-                arg_snip.into_owned()
-            } else {
-                format!("{{ /* snippet */ {arg_snip} }}")
-            };
             let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(msrvs::BOOL_THEN_SOME) {
                 "then_some"
             } else {
-                method_body.insert_str(0, "|| ");
                 "then"
             };
 
-            let help =
-                format!("consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",);
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 IF_THEN_SOME_ELSE_NONE,
                 expr.span,
                 format!("this could be simplified with `bool::{method_name}`"),
-                None,
-                help,
+                |diag| {
+                    let mut app = Applicability::Unspecified;
+                    let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
+                        .maybe_par()
+                        .to_string();
+                    let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
+                    let method_body = if let Some(first_stmt) = then_block.stmts.first() {
+                        let (block_snippet, _) =
+                            snippet_with_context(cx, first_stmt.span.until(then_arg.span), ctxt, "..", &mut app);
+                        let closure = if method_name == "then" { "|| " } else { "" };
+                        format!("{closure} {{ {block_snippet}; {arg_snip} }}")
+                    } else {
+                        arg_snip.into_owned()
+                    };
+
+                    diag.span_suggestion(
+                        expr.span,
+                        "try",
+                        format!("{cond_snip}.{method_name}({method_body})"),
+                        app,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 344a04e6e7e..e56f33f8dcf 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -1,7 +1,7 @@
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 
-use rustc_errors::Diag;
+use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
@@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt};
 use clippy_utils::ty::is_type_diagnostic_item;
 
@@ -77,33 +77,32 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                 &generics_snip[1..generics_snip.len() - 1]
             };
 
-            multispan_sugg(
-                diag,
-                "consider adding a type parameter",
-                vec![
-                    (
-                        generics_suggestion_span,
-                        format!(
-                            "<{generics_snip}{}S: ::std::hash::BuildHasher{}>",
-                            if generics_snip.is_empty() { "" } else { ", " },
-                            if vis.suggestions.is_empty() {
-                                ""
-                            } else {
-                                // request users to add `Default` bound so that generic constructors can be used
-                                " + Default"
-                            },
-                        ),
-                    ),
-                    (
-                        target.span(),
-                        format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
+            let mut suggestions = vec![
+                (
+                    generics_suggestion_span,
+                    format!(
+                        "<{generics_snip}{}S: ::std::hash::BuildHasher{}>",
+                        if generics_snip.is_empty() { "" } else { ", " },
+                        if vis.suggestions.is_empty() {
+                            ""
+                        } else {
+                            // request users to add `Default` bound so that generic constructors can be used
+                            " + Default"
+                        },
                     ),
-                ],
+                ),
+                (
+                    target.span(),
+                    format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
+                ),
+            ];
+            suggestions.extend(vis.suggestions);
+
+            diag.multipart_suggestion(
+                "add a type parameter for `BuildHasher`",
+                suggestions,
+                Applicability::MaybeIncorrect,
             );
-
-            if !vis.suggestions.is_empty() {
-                multispan_sugg(diag, "...and use generic constructor", vis.suggestions);
-            }
         }
 
         if !cx.effective_visibilities.is_exported(item.owner_id.def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index a102b434cfa..b926e1e62ba 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context, wal
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro};
 use core::ops::ControlFlow;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -45,8 +45,6 @@ declare_clippy_lint! {
 declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]);
 
 fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
-    let mut app = Applicability::MachineApplicable;
-    let snip = snippet_with_applicability(cx, span, "..", &mut app);
     span_lint_hir_and_then(
         cx,
         IMPLICIT_RETURN,
@@ -54,14 +52,20 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
         span,
         "missing `return` statement",
         |diag| {
-            diag.span_suggestion(span, "add `return` as shown", format!("return {snip}"), app);
+            let mut app = Applicability::MachineApplicable;
+            let snip = snippet_with_applicability(cx, span, "..", &mut app);
+            diag.span_suggestion_with_style(
+                span,
+                "add `return` as shown",
+                format!("return {snip}"),
+                app,
+                SuggestionStyle::ShowAlways,
+            );
         },
     );
 }
 
 fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, expr_span: Span) {
-    let mut app = Applicability::MachineApplicable;
-    let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0;
     span_lint_hir_and_then(
         cx,
         IMPLICIT_RETURN,
@@ -69,11 +73,14 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp
         break_span,
         "missing `return` statement",
         |diag| {
-            diag.span_suggestion(
+            let mut app = Applicability::MachineApplicable;
+            let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0;
+            diag.span_suggestion_with_style(
                 break_span,
                 "change `break` to `return` as shown",
                 format!("return {snip}"),
                 app,
+                SuggestionStyle::ShowAlways,
             );
         },
     );
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index f225c6e7f04..dd5908553e5 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_context;
@@ -117,11 +117,11 @@ fn get_int_max(ty: Ty<'_>) -> Option<u128> {
 
 fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> {
     if let ExprKind::Binary(op, l, r) = expr.kind {
-        let tr = cx.typeck_results();
-        if let Some(Constant::Int(c)) = constant(cx, tr, r) {
+        let ecx = ConstEvalCtxt::new(cx);
+        if let Some(Constant::Int(c)) = ecx.eval(r) {
             return Some((c, op.node, l));
         };
-        if let Some(Constant::Int(c)) = constant(cx, tr, l) {
+        if let Some(Constant::Int(c)) = ecx.eval(l) {
             return Some((c, invert_op(op.node)?, r));
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
index 12ca6d43b27..0ef5b803a89 100644
--- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -55,7 +55,6 @@ impl IncompatibleMsrv {
         }
     }
 
-    #[allow(clippy::cast_lossless)]
     fn get_def_id_version(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> RustcVersion {
         if let Some(version) = self.is_above_msrv.get(&def_id) {
             return *version;
@@ -67,9 +66,9 @@ impl IncompatibleMsrv {
                     since: StableSince::Version(version),
                     ..
                 } => Some(RustcVersion::new(
-                    version.major as _,
-                    version.minor as _,
-                    version.patch as _,
+                    version.major.into(),
+                    version.minor.into(),
+                    version.patch.into(),
                 )),
                 _ => None,
             }) {
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 526b4e1fba0..2f9661c9ea3 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLet;
 use clippy_utils::ty::is_copy;
@@ -246,7 +246,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
                 && let parent_id = cx.tcx.parent_hir_id(expr.hir_id)
                 && let hir::Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id)
                 && let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind
-                && let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr)
+                && let Some(Constant::Int(index_value)) = ConstEvalCtxt::new(cx).eval(index_expr)
                 && let Ok(index_value) = index_value.try_into()
                 && index_value < max_suggested_slice
 
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 6729c7c8d10..3ac50b8f1fb 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -1,7 +1,7 @@
 //! lint on indexing and slicing operations
 
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::ty::{deref_chain, get_adt_inherent_method};
 use clippy_utils::{higher, is_from_proc_macro};
@@ -70,8 +70,6 @@ declare_clippy_lint! {
     ///
     /// Use instead:
     /// ```no_run
-    /// # #![allow(unused)]
-    ///
     /// # let x = vec![0; 5];
     /// # let y = [0, 1, 2, 3];
     /// x.get(2);
@@ -179,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                         return;
                     }
                     // Index is a constant uint.
-                    if let Some(constant) = constant(cx, cx.typeck_results(), index) {
+                    if let Some(constant) = ConstEvalCtxt::new(cx).eval(index) {
                         // only `usize` index is legal in rust array index
                         // leave other type to rustc
                         if let Constant::Int(off) = constant
@@ -217,14 +215,15 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
 /// Returns a tuple of options with the start and end (exclusive) values of
 /// the range. If the start or end is not constant, None is returned.
 fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) {
-    let s = range.start.map(|expr| constant(cx, cx.typeck_results(), expr));
+    let ecx = ConstEvalCtxt::new(cx);
+    let s = range.start.map(|expr| ecx.eval(expr));
     let start = match s {
         Some(Some(Constant::Int(x))) => Some(x),
         Some(_) => None,
         None => Some(0),
     };
 
-    let e = range.end.map(|expr| constant(cx, cx.typeck_results(), expr));
+    let e = range.end.map(|expr| ecx.eval(expr));
     let end = match e {
         Some(Some(Constant::Int(x))) => {
             if range.limits == RangeLimits::Closed {
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index fa7e7f6b76d..676d50c4951 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -41,7 +41,6 @@ declare_clippy_lint! {
     /// ### Example
     /// ```no_run
     /// let infinite_iter = 0..;
-    /// # #[allow(unused)]
     /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
     /// ```
     #[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 0d3786dad4b..9eed7aa9243 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -1,6 +1,6 @@
 //! lint on inherent implementations
 
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::LocalDefId;
@@ -105,13 +105,14 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
         // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
         lint_spans.sort_by_key(|x| x.0.lo());
         for (span, first_span) in lint_spans {
-            span_lint_and_note(
+            span_lint_and_then(
                 cx,
                 MULTIPLE_INHERENT_IMPL,
                 span,
                 "multiple implementations of this structure",
-                Some(first_span),
-                "first implementation here",
+                |diag| {
+                    diag.span_note(first_span, "first implementation here");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index 30f2285bdd2..1929fbded3b 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -7,7 +7,7 @@ use rustc_span::Span;
 
 use clippy_utils::comparisons;
 use clippy_utils::comparisons::Rel;
-use clippy_utils::consts::{constant_full_int, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet;
 
@@ -95,7 +95,7 @@ fn upcast_comparison_bounds_err<'tcx>(
     invert: bool,
 ) {
     if let Some((lb, ub)) = lhs_bounds {
-        if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
+        if let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs) {
             if rel == Rel::Eq || rel == Rel::Ne {
                 if norm_rhs_val < lb || norm_rhs_val > ub {
                     err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index c67da689aae..f2f841dcec3 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::root_macro_call_first_node;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
@@ -66,16 +66,18 @@ impl LateLintPass<'_> for LargeIncludeFile {
             && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
                 || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
         {
-            span_lint_and_note(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 LARGE_INCLUDE_FILE,
                 expr.span.source_callsite(),
                 "attempted to include a large file",
-                None,
-                format!(
-                    "the configuration allows a maximum size of {} bytes",
-                    self.max_file_size
-                ),
+                |diag| {
+                    diag.note(format!(
+                        "the configuration allows a maximum size of {} bytes",
+                        self.max_file_size
+                    ));
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 8fa63f3e8fd..b522c22a44d 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
 use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
 use rustc_hir::{LetStmt, LocalSource, PatKind};
@@ -149,43 +149,53 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                 GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
             });
             if contains_sync_guard {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_LOCK,
                     local.span,
                     "non-binding `let` on a synchronization lock",
-                    None,
-                    "consider using an underscore-prefixed named \
-                            binding or dropping explicitly with `std::mem::drop`",
+                    |diag| {
+                        diag.help(
+                            "consider using an underscore-prefixed named \
+                                binding or dropping explicitly with `std::mem::drop`",
+                        );
+                    },
                 );
             } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
                 && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[])
             {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_FUTURE,
                     local.span,
                     "non-binding `let` on a future",
-                    None,
-                    "consider awaiting the future or dropping explicitly with `std::mem::drop`",
+                    |diag| {
+                        diag.help("consider awaiting the future or dropping explicitly with `std::mem::drop`");
+                    },
                 );
             } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_MUST_USE,
                     local.span,
                     "non-binding `let` on an expression with `#[must_use]` type",
-                    None,
-                    "consider explicitly using expression value",
+                    |diag| {
+                        diag.help("consider explicitly using expression value");
+                    },
                 );
             } else if is_must_use_func_call(cx, init) {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_MUST_USE,
                     local.span,
                     "non-binding `let` on a result of a `#[must_use]` function",
-                    None,
-                    "consider explicitly using function result",
+                    |diag| {
+                        diag.help("consider explicitly using function result");
+                    },
                 );
             }
 
@@ -204,18 +214,22 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                     return;
                 }
 
-                span_lint_and_help(
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_UNTYPED,
                     local.span,
                     "non-binding `let` without a type annotation",
-                    Some(Span::new(
-                        local.pat.span.hi(),
-                        local.pat.span.hi() + BytePos(1),
-                        local.pat.span.ctxt(),
-                        local.pat.span.parent(),
-                    )),
-                    "consider adding a type annotation",
+                    |diag| {
+                        diag.span_help(
+                            Span::new(
+                                local.pat.span.hi(),
+                                local.pat.span.hi() + BytePos(1),
+                                local.pat.span.ctxt(),
+                                local.pat.span.parent(),
+                            ),
+                            "consider adding a type annotation",
+                        );
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.deprecated.rs b/src/tools/clippy/clippy_lints/src/lib.deprecated.rs
deleted file mode 100644
index 0d21261822d..00000000000
--- a/src/tools/clippy/clippy_lints/src/lib.deprecated.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-{
-    store.register_removed(
-        "clippy::should_assert_eq",
-        "`assert!()` will be more flexible with RFC 2011",
-    );
-    store.register_removed(
-        "clippy::extend_from_slice",
-        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
-    );
-    store.register_removed(
-        "clippy::range_step_by_zero",
-        "`iterator.step_by(0)` panics nowadays",
-    );
-    store.register_removed(
-        "clippy::unstable_as_slice",
-        "`Vec::as_slice` has been stabilized in 1.7",
-    );
-    store.register_removed(
-        "clippy::unstable_as_mut_slice",
-        "`Vec::as_mut_slice` has been stabilized in 1.7",
-    );
-    store.register_removed(
-        "clippy::misaligned_transmute",
-        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
-    );
-    store.register_removed(
-        "clippy::assign_ops",
-        "using compound assignment operators (e.g., `+=`) is harmless",
-    );
-    store.register_removed(
-        "clippy::if_let_redundant_pattern_matching",
-        "this lint has been changed to redundant_pattern_matching",
-    );
-    store.register_removed(
-        "clippy::unsafe_vector_initialization",
-        "the replacement suggested by this lint had substantially different behavior",
-    );
-    store.register_removed(
-        "clippy::unused_collect",
-        "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint",
-    );
-    store.register_removed(
-        "clippy::replace_consts",
-        "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants",
-    );
-    store.register_removed(
-        "clippy::regex_macro",
-        "the regex! macro has been removed from the regex crate in 2018",
-    );
-    store.register_removed(
-        "clippy::find_map",
-        "this lint has been replaced by `manual_find_map`, a more specific lint",
-    );
-    store.register_removed(
-        "clippy::filter_map",
-        "this lint has been replaced by `manual_filter_map`, a more specific lint",
-    );
-    store.register_removed(
-        "clippy::pub_enum_variant_names",
-        "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items",
-    );
-    store.register_removed(
-        "clippy::wrong_pub_self_convention",
-        "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items",
-    );
-    store.register_removed(
-        "clippy::maybe_misused_cfg",
-        "this lint has been replaced by `unexpected_cfgs`",
-    );
-    store.register_removed(
-        "clippy::mismatched_target_os",
-        "this lint has been replaced by `unexpected_cfgs`",
-    );
-}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index a388b6b2eaa..ce13a9afef5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -13,7 +13,6 @@
 #![feature(stmt_expr_attributes)]
 #![feature(unwrap_infallible)]
 #![recursion_limit = "512"]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(
     clippy::missing_docs_in_private_items,
     clippy::must_use_candidate,
@@ -64,13 +63,11 @@ extern crate clippy_utils;
 #[macro_use]
 extern crate declare_clippy_lint;
 
-#[cfg(feature = "internal")]
-pub mod deprecated_lints;
 #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 mod utils;
 
 mod declared_lints;
-mod renamed_lints;
+mod deprecated_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absolute_paths;
@@ -372,6 +369,7 @@ mod unsafe_removed_from_name;
 mod unused_async;
 mod unused_io_amount;
 mod unused_peekable;
+mod unused_result_ok;
 mod unused_rounding;
 mod unused_self;
 mod unused_unit;
@@ -495,7 +493,7 @@ pub fn explain(name: &str) -> i32 {
         // Check if the lint has configuration
         let mut mdconf = get_configuration_metadata();
         let name = name.to_ascii_lowercase();
-        mdconf.retain(|cconf| cconf.lints.contains(&name));
+        mdconf.retain(|cconf| cconf.lints.contains(&&*name));
         if !mdconf.is_empty() {
             println!("### Configuration for {}:\n", info.lint.name_lower());
             for conf in mdconf {
@@ -531,10 +529,14 @@ fn register_categories(store: &mut rustc_lint::LintStore) {
 /// Used in `./src/driver.rs`.
 #[expect(clippy::too_many_lines)]
 pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
-    register_removed_non_tool_lints(store);
     register_categories(store);
 
-    include!("lib.deprecated.rs");
+    for (old_name, new_name) in deprecated_lints::RENAMED {
+        store.register_renamed(old_name, new_name);
+    }
+    for (name, reason) in deprecated_lints::DEPRECATED {
+        store.register_removed(name, reason);
+    }
 
     #[cfg(feature = "internal")]
     {
@@ -669,6 +671,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(conf)));
     store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
     store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
+    store.register_late_pass(|_| Box::new(unused_result_ok::UnusedResultOk));
     store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
     store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
     store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
@@ -818,7 +821,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(conf)));
     store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate));
     store.register_late_pass(move |_| Box::new(operators::Operators::new(conf)));
-    store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
+    store.register_late_pass(move |_| Box::new(std_instead_of_core::StdReexports::new(conf)));
     store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(conf)));
     store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
     store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(conf)));
@@ -907,68 +910,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe::new(conf)));
     store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(conf)));
     store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
-    store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
+    store.register_late_pass(|_| Box::new(set_contains_or_insert::SetContainsOrInsert));
     store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice));
     store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
-
-#[rustfmt::skip]
-fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
-    store.register_removed(
-        "should_assert_eq",
-        "`assert!()` will be more flexible with RFC 2011",
-    );
-    store.register_removed(
-        "extend_from_slice",
-        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
-    );
-    store.register_removed(
-        "range_step_by_zero",
-        "`iterator.step_by(0)` panics nowadays",
-    );
-    store.register_removed(
-        "unstable_as_slice",
-        "`Vec::as_slice` has been stabilized in 1.7",
-    );
-    store.register_removed(
-        "unstable_as_mut_slice",
-        "`Vec::as_mut_slice` has been stabilized in 1.7",
-    );
-    store.register_removed(
-        "misaligned_transmute",
-        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
-    );
-    store.register_removed(
-        "assign_ops",
-        "using compound assignment operators (e.g., `+=`) is harmless",
-    );
-    store.register_removed(
-        "if_let_redundant_pattern_matching",
-        "this lint has been changed to redundant_pattern_matching",
-    );
-    store.register_removed(
-        "unsafe_vector_initialization",
-        "the replacement suggested by this lint had substantially different behavior",
-    );
-    store.register_removed(
-        "reverse_range_loop",
-        "this lint is now included in reversed_empty_ranges",
-    );
-}
-
-/// Register renamed lints.
-///
-/// Used in `./src/driver.rs`.
-pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
-    for (old_name, new_name) in renamed_lints::RENAMED_LINTS {
-        ls.register_renamed(old_name, new_name);
-    }
-}
-
-// only exists to let the dogfood integration test works.
-// Don't run clippy as an executable directly
-#[allow(dead_code)]
-fn main() {
-    panic!("Please use the cargo-clippy executable");
-}
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index b685d1dad1a..259e4d6c08f 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -2,13 +2,13 @@
 //! floating-point literal expressions.
 
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::numeric_literal::{NumericLiteral, Radix};
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{Expr, ExprKind, LitKind};
 use rustc_ast::token;
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -159,63 +159,39 @@ enum WarningType {
 }
 
 impl WarningType {
-    fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: Span) {
+    fn lint_and_text(&self) -> (&'static Lint, &'static str, &'static str) {
         match self {
-            Self::MistypedLiteralSuffix => span_lint_and_sugg(
-                cx,
+            Self::MistypedLiteralSuffix => (
                 MISTYPED_LITERAL_SUFFIXES,
-                span,
                 "mistyped literal suffix",
                 "did you mean to write",
-                suggested_format,
-                Applicability::MaybeIncorrect,
             ),
-            Self::UnreadableLiteral => span_lint_and_sugg(
-                cx,
-                UNREADABLE_LITERAL,
-                span,
-                "long literal lacking separators",
-                "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
-            ),
-            Self::LargeDigitGroups => span_lint_and_sugg(
-                cx,
-                LARGE_DIGIT_GROUPS,
-                span,
-                "digit groups should be smaller",
-                "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
-            ),
-            Self::InconsistentDigitGrouping => span_lint_and_sugg(
-                cx,
+            Self::UnreadableLiteral => (UNREADABLE_LITERAL, "long literal lacking separators", "consider"),
+            Self::LargeDigitGroups => (LARGE_DIGIT_GROUPS, "digit groups should be smaller", "consider"),
+            Self::InconsistentDigitGrouping => (
                 INCONSISTENT_DIGIT_GROUPING,
-                span,
                 "digits grouped inconsistently by underscores",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-            Self::DecimalRepresentation => span_lint_and_sugg(
-                cx,
+            Self::DecimalRepresentation => (
                 DECIMAL_LITERAL_REPRESENTATION,
-                span,
                 "integer literal has a better hexadecimal representation",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-            Self::UnusualByteGroupings => span_lint_and_sugg(
-                cx,
+            Self::UnusualByteGroupings => (
                 UNUSUAL_BYTE_GROUPINGS,
-                span,
                 "digits of hex, binary or octal literal not in groups of equal size",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-        };
+        }
+    }
+
+    fn display(&self, num_lit: &NumericLiteral<'_>, cx: &EarlyContext<'_>, span: Span) {
+        let (lint, message, try_msg) = self.lint_and_text();
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, lint, span, message, |diag| {
+            diag.span_suggestion(span, try_msg, num_lit.format(), Applicability::MaybeIncorrect);
+        });
     }
 }
 
@@ -293,7 +269,7 @@ impl LiteralDigitGrouping {
                     WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => true,
                 };
                 if should_warn {
-                    warning_type.display(num_lit.format(), cx, span);
+                    warning_type.display(&num_lit, cx, span);
                 }
             }
         }
@@ -346,11 +322,14 @@ impl LiteralDigitGrouping {
                 }
             }
             *part = main_part;
-            let mut sugg = num_lit.format();
-            sugg.push('_');
-            sugg.push(missing_char);
-            sugg.push_str(last_group);
-            WarningType::MistypedLiteralSuffix.display(sugg, cx, span);
+            let (lint, message, try_msg) = WarningType::MistypedLiteralSuffix.lint_and_text();
+            span_lint_and_then(cx, lint, span, message, |diag| {
+                let mut sugg = num_lit.format();
+                sugg.push('_');
+                sugg.push(missing_char);
+                sugg.push_str(last_group);
+                diag.span_suggestion(span, try_msg, sugg, Applicability::MaybeIncorrect);
+            });
             false
         } else {
             true
@@ -471,7 +450,7 @@ impl DecimalLiteralRepresentation {
             let hex = format!("{val:#X}");
             let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
             let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| {
-                warning_type.display(num_lit.format(), cx, span);
+                warning_type.display(&num_lit, cx, span);
             });
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index f0ee64d714e..73a23615c2d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -2,6 +2,7 @@ use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{get_enclosing_block, is_integer_const};
+use rustc_ast::Label;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_block, walk_expr};
 use rustc_hir::{Expr, Pat};
@@ -17,6 +18,7 @@ pub(super) fn check<'tcx>(
     arg: &'tcx Expr<'_>,
     body: &'tcx Expr<'_>,
     expr: &'tcx Expr<'_>,
+    label: Option<Label>,
 ) {
     // Look for variables that are incremented once per loop iteration.
     let mut increment_visitor = IncrementVisitor::new(cx);
@@ -34,7 +36,7 @@ pub(super) fn check<'tcx>(
             {
                 let mut applicability = Applicability::MaybeIncorrect;
                 let span = expr.span.with_hi(arg.span.hi());
-
+                let loop_label = label.map_or(String::new(), |l| format!("{}: ", l.ident.name));
                 let int_name = match ty.map(Ty::kind) {
                     // usize or inferred
                     Some(ty::Uint(UintTy::Usize)) | None => {
@@ -45,7 +47,7 @@ pub(super) fn check<'tcx>(
                             format!("the variable `{name}` is used as a loop counter"),
                             "consider using",
                             format!(
-                                "for ({name}, {}) in {}.enumerate()",
+                                "{loop_label}for ({name}, {}) in {}.enumerate()",
                                 snippet_with_applicability(cx, pat.span, "item", &mut applicability),
                                 make_iterator_snippet(cx, arg, &mut applicability),
                             ),
@@ -68,7 +70,7 @@ pub(super) fn check<'tcx>(
                             span,
                             "consider using",
                             format!(
-                                "for ({name}, {}) in (0_{int_name}..).zip({})",
+                                "{loop_label}for ({name}, {}) in (0_{int_name}..).zip({})",
                                 snippet_with_applicability(cx, pat.span, "item", &mut applicability),
                                 make_iterator_snippet(cx, arg, &mut applicability),
                             ),
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
index 6922533fbe9..185d834beca 100644
--- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
@@ -1,8 +1,9 @@
 use super::FOR_KV_MAP;
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{pat_is_wild, sugg};
+use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
@@ -40,13 +41,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
                     format!("you seem to want to iterate on a map's {kind}s"),
                     |diag| {
                         let map = sugg::Sugg::hir(cx, arg, "map");
-                        multispan_sugg(
-                            diag,
+                        diag.multipart_suggestion(
                             "use the corresponding method",
                             vec![
                                 (pat_span, snippet(cx, new_pat_span, kind).into_owned()),
                                 (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_par())),
                             ],
+                            Applicability::MachineApplicable,
                         );
                     },
                 );
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
index b00a082bb8c..57434f35544 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::{match_def_path, paths, SpanlessEq};
 use rustc_errors::Applicability;
@@ -38,11 +38,10 @@ fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>,
             };
 
             let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, ".."));
-            multispan_sugg_with_applicability(
-                diag,
+            diag.multipart_suggestion(
                 "consider using a `while..let` loop",
+                vec![(loop_span, loop_replacement), (pop_span, pop_replacement)],
                 Applicability::MachineApplicable,
-                [(loop_span, loop_replacement), (pop_span, pop_replacement)],
             );
         },
     );
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 7c2a8098af2..92ccc0cc0a1 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -25,6 +25,7 @@ mod while_let_on_iterator;
 use clippy_config::msrvs::Msrv;
 use clippy_config::Conf;
 use clippy_utils::higher;
+use rustc_ast::Label;
 use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -448,7 +449,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.80.0"]
     pub WHILE_FLOAT,
     nursery,
-    "while loops comaparing floating point values"
+    "while loops comparing floating point values"
 }
 
 declare_clippy_lint! {
@@ -760,6 +761,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
             body,
             loop_id,
             span,
+            label,
         }) = for_loop
         {
             // we don't want to check expanded macros
@@ -768,7 +770,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
             if body.span.from_expansion() {
                 return;
             }
-            self.check_for_loop(cx, pat, arg, body, expr, span);
+            self.check_for_loop(cx, pat, arg, body, expr, span, label);
             if let ExprKind::Block(block, _) = body.kind {
                 never_loop::check(cx, block, loop_id, span, for_loop.as_ref());
             }
@@ -808,6 +810,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 }
 
 impl Loops {
+    #[allow(clippy::too_many_arguments)]
     fn check_for_loop<'tcx>(
         &self,
         cx: &LateContext<'tcx>,
@@ -816,11 +819,12 @@ impl Loops {
         body: &'tcx Expr<'_>,
         expr: &'tcx Expr<'_>,
         span: Span,
+        label: Option<Label>,
     ) {
         let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr);
         if !is_manual_memcpy_triggered {
             needless_range_loop::check(cx, pat, arg, body, expr);
-            explicit_counter_loop::check(cx, pat, arg, body, expr);
+            explicit_counter_loop::check(cx, pat, arg, body, expr, label);
         }
         self.check_for_loop_arg(cx, pat, arg);
         for_kv_map::check(cx, pat, arg, body);
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index de7ec81bc01..e18e4374667 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -1,11 +1,12 @@
 use super::NEEDLESS_RANGE_LOOP;
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::has_iter_method;
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq};
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BinOpKind, BorrowKind, Closure, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath};
@@ -145,8 +146,7 @@ pub(super) fn check<'tcx>(
                         arg.span,
                         format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
                         |diag| {
-                            multispan_sugg(
-                                diag,
+                            diag.multipart_suggestion(
                                 "consider using an iterator and enumerate()",
                                 vec![
                                     (pat.span, format!("({}, <item>)", ident.name)),
@@ -155,6 +155,7 @@ pub(super) fn check<'tcx>(
                                         format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
                                     ),
                                 ],
+                                Applicability::HasPlaceholders,
                             );
                         },
                     );
@@ -171,10 +172,10 @@ pub(super) fn check<'tcx>(
                         arg.span,
                         format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
                         |diag| {
-                            multispan_sugg(
-                                diag,
+                            diag.multipart_suggestion(
                                 "consider using an iterator",
                                 vec![(pat.span, "<item>".to_string()), (arg.span, repl)],
+                                Applicability::HasPlaceholders,
                             );
                         },
                     );
diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
index 40ccfec02be..51e21aa9734 100644
--- a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
@@ -1,7 +1,8 @@
 use super::UNUSED_ENUMERATE_INDEX;
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::{pat_is_wild, sugg};
+use rustc_errors::Applicability;
 use rustc_hir::def::DefKind;
 use rustc_hir::{Expr, ExprKind, Pat, PatKind};
 use rustc_lint::LateContext;
@@ -28,13 +29,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_
             "you seem to use `.enumerate()` and immediately discard the index",
             |diag| {
                 let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter");
-                multispan_sugg(
-                    diag,
+                diag.multipart_suggestion(
                     "remove the `.enumerate()` call",
                     vec![
                         (pat.span, snippet(cx, elem.span, "..").into_owned()),
                         (arg.span, base_iter.to_string()),
                     ],
+                    Applicability::MachineApplicable,
                 );
             },
         );
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
index e7b3a2c4973..cc1bd5929d0 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
@@ -1,5 +1,5 @@
 use super::WHILE_IMMUTABLE_CONDITION;
-use clippy_utils::consts::constant;
+use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::usage::mutated_variables;
 use rustc_hir::def::{DefKind, Res};
@@ -10,7 +10,7 @@ use rustc_lint::LateContext;
 use std::ops::ControlFlow;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
-    if constant(cx, cx.typeck_results(), cond).is_some() {
+    if ConstEvalCtxt::new(cx).eval(cond).is_some() {
         // A pure constant condition (e.g., `while false`) is not linted.
         return;
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 194dd4752f9..c171fa1c622 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -14,7 +14,7 @@ use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let Some(higher::WhileLet { if_then, let_pat, let_expr, .. }) = higher::WhileLet::hir(expr)
+    if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr)
         // check for `Some(..)` pattern
         && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
         && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
@@ -27,6 +27,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         && !uses_iter(cx, &iter_expr_struct, if_then)
     {
         let mut applicability = Applicability::MachineApplicable;
+
+        let loop_label = label.map_or(String::new(), |l| format!("{}: ", l.ident.name));
+
         let loop_var = if let Some(some_pat) = some_pat.first() {
             if is_refutable(cx, some_pat) {
                 // Refutable patterns don't work with for loops.
@@ -57,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             expr.span.with_hi(let_expr.span.hi()),
             "this loop could be written as a `for` loop",
             "try",
-            format!("for {loop_var} in {iterator}{by_ref}"),
+            format!("{loop_label}for {loop_var} in {iterator}{by_ref}"),
             applicability,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index a79ad018a04..4123c933660 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -1,13 +1,13 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::higher::If;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::is_const_evaluatable;
 use clippy_utils::{
-    eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks,
+    eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, peel_blocks,
     peel_blocks_with_stmt, MaybePath,
 };
 use itertools::Itertools;
@@ -122,8 +122,9 @@ impl<'tcx> ClampSuggestion<'tcx> {
         if max_type != min_type {
             return false;
         }
-        if let Some(max) = constant(cx, cx.typeck_results(), self.params.max)
-            && let Some(min) = constant(cx, cx.typeck_results(), self.params.min)
+        let ecx = ConstEvalCtxt::new(cx);
+        if let Some(max) = ecx.eval(self.params.max)
+            && let Some(min) = ecx.eval(self.params.min)
             && let Some(ord) = Constant::partial_cmp(cx.tcx, max_type, &min, &max)
         {
             ord != Ordering::Greater
@@ -146,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
         if !self.msrv.meets(msrvs::CLAMP) {
             return;
         }
-        if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
+        if !expr.span.from_expansion() && !is_in_const_context(cx) {
             let suggestion = is_if_elseif_else_pattern(cx, expr)
                 .or_else(|| is_max_min_pattern(cx, expr))
                 .or_else(|| is_call_max_min_pattern(cx, expr))
@@ -159,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
     }
 
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
-        if !self.msrv.meets(msrvs::CLAMP) || in_constant(cx, block.hir_id) {
+        if !self.msrv.meets(msrvs::CLAMP) || is_in_const_context(cx) {
             return;
         }
         for suggestion in is_two_if_pattern(cx, block) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index 03416ba96de..6bdc79129a9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{is_from_proc_macro, path_to_local};
@@ -95,8 +95,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
                     || cx.tcx.features().declared(sym!(const_float_classify))
             )
             && let [first, second, const_1, const_2] = exprs
-            && let Some(const_1) = constant(cx, cx.typeck_results(), const_1)
-            && let Some(const_2) = constant(cx, cx.typeck_results(), const_2)
+            && let ecx = ConstEvalCtxt::new(cx)
+            && let Some(const_1) = ecx.eval(const_1)
+            && let Some(const_2) = ecx.eval(const_2)
             && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
             // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
             // case somebody does that for some reason
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index a9f21d34e4c..31c37c3bc3b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -3,7 +3,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{higher, in_constant, path_to_local, peel_ref_operators};
+use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators};
 use rustc_ast::ast::RangeLimits;
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_errors::Applicability;
@@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             return;
         }
 
-        if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) {
+        if is_in_const_context(cx) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 78a750f0dcd..6cf5d272d7d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -1,9 +1,9 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant_full_int, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::{in_constant, path_to_local};
+use clippy_utils::{is_in_const_context, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             && add_rhs.span.ctxt() == ctxt
             && !in_external_macro(cx.sess(), expr.span)
             && self.msrv.meets(msrvs::REM_EUCLID)
-            && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !in_constant(cx, expr.hir_id))
+            && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !is_in_const_context(cx))
             && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs)
             && let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs)
             && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
@@ -117,7 +117,7 @@ fn check_for_either_unsigned_int_constant<'a>(
 }
 
 fn check_for_unsigned_int_constant<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<u128> {
-    let int_const = constant_full_int(cx, cx.typeck_results(), expr)?;
+    let int_const = ConstEvalCtxt::new(cx).eval_full_int(expr)?;
     match int_const {
         FullInt::S(s) => s.try_into().ok(),
         FullInt::U(u) => Some(u),
diff --git a/src/tools/clippy/clippy_lints/src/manual_rotate.rs b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
index a517a4d5075..07537fc65c0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rotate.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
@@ -1,6 +1,6 @@
 use std::fmt::Display;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg;
 use rustc_errors::Applicability;
@@ -66,7 +66,7 @@ fn parse_shift<'tcx>(
             BinOpKind::Shr => ShiftDirection::Right,
             _ => return None,
         };
-        let const_expr = constant(cx, cx.typeck_results(), r)?;
+        let const_expr = ConstEvalCtxt::new(cx).eval(r)?;
         if let Constant::Int(shift) = const_expr {
             return Some((dir, shift, l));
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 429ee2637c2..b24a0f4695a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::{expr_or_init, in_constant, std_or_core};
+use clippy_utils::{expr_or_init, is_in_const_context, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
             && BinOpKind::Mul == op.node
             && !expr.span.from_expansion()
             // Does not apply inside const because size_of_val is not cost in stable.
-            && !in_constant(cx, expr.hir_id)
+            && !is_in_const_context(cx)
             && let Some(receiver) = simplify(cx, left, right)
         {
             let ctxt = expr.span.ctxt();
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 686ecccf829..85cabd2800a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -1,11 +1,12 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::usage::mutated_variables;
 use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
 use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
@@ -14,6 +15,7 @@ use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::source_map::Spanned;
 use rustc_span::Span;
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -108,19 +110,19 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
                     format!("stripping a {kind_word} manually"),
                     |diag| {
                         diag.span_note(test_span, format!("the {kind_word} was tested here"));
-                        multispan_sugg(
-                            diag,
+                        diag.multipart_suggestion(
                             format!("try using the `strip_{kind_word}` method"),
-                            vec![(
+                            iter::once((
                                 test_span,
                                 format!(
                                     "if let Some(<stripped>) = {}.strip_{kind_word}({}) ",
                                     snippet(cx, target_arg.span, ".."),
                                     snippet(cx, pattern.span, "..")
                                 ),
-                            )]
-                            .into_iter()
-                            .chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
+                            ))
+                            .chain(strippings.into_iter().map(|span| (span, "<stripped>".into())))
+                            .collect(),
+                            Applicability::HasPlaceholders,
                         );
                     },
                 );
@@ -145,7 +147,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E
 
 // Returns the length of the `expr` if it's a constant string or char.
 fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
-    let value = constant(cx, cx.typeck_results(), expr)?;
+    let value = ConstEvalCtxt::new(cx).eval(expr)?;
     match value {
         Constant::Str(value) => Some(value.len() as u128),
         Constant::Char(value) => Some(value.len_utf8() as u128),
@@ -183,9 +185,9 @@ fn peel_ref<'a>(expr: &'a Expr<'_>) -> &'a Expr<'a> {
     }
 }
 
-// Find expressions where `target` is stripped using the length of `pattern`.
-// We'll suggest replacing these expressions with the result of the `strip_{prefix,suffix}`
-// method.
+/// Find expressions where `target` is stripped using the length of `pattern`.
+/// We'll suggest replacing these expressions with the result of the `strip_{prefix,suffix}`
+/// method.
 fn find_stripping<'tcx>(
     cx: &LateContext<'tcx>,
     strip_kind: StripKind,
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
index f1acc4b2174..8f8390b6f3f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -10,7 +10,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::IfLetOrMatch;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment};
+use clippy_utils::{is_default_equivalent, is_in_const_context, peel_blocks, span_contains_comment};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -174,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr)
             && !expr.span.from_expansion()
-            && !in_constant(cx, expr.hir_id)
+            && !is_in_const_context(cx)
         {
             handle(cx, if_let_or_match, expr);
         }
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index 85a08f81c2f..2d4c8daf5cb 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::constant_simple;
+use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -69,7 +69,7 @@ fn check_and_lint<'tcx>(
         && let Some(ty_name) = find_type_name(cx, ty)
         && let Some(or_body_snippet) = snippet_opt(cx, else_expr.span)
         && let Some(indent) = indent_of(cx, expr.span)
-        && constant_simple(cx, cx.typeck_results(), else_expr).is_some()
+        && ConstEvalCtxt::new(cx).eval_simple(else_expr).is_some()
     {
         lint(cx, expr, let_expr, ty_name, or_body_snippet, indent);
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
index aba4c85c59e..5445ee1f042 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use core::iter::once;
@@ -54,7 +54,11 @@ where
 
     span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
         if !expr.span.from_expansion() {
-            multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
+            diag.multipart_suggestion(
+                msg,
+                first_sugg.chain(remaining_suggs).collect(),
+                Applicability::MachineApplicable,
+            );
         }
     });
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 8d22ceb47f8..91e40e4275c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
 use rustc_errors::Applicability;
@@ -148,23 +148,27 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
             Applicability::MaybeIncorrect,
         ),
         variants => {
-            let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
-            let message = if adt_def.is_variant_list_non_exhaustive() || has_external_hidden {
-                suggestions.push("_".into());
-                "wildcard matches known variants and will also match future added variants"
+            let (message, add_wildcard) = if adt_def.is_variant_list_non_exhaustive() || has_external_hidden {
+                (
+                    "wildcard matches known variants and will also match future added variants",
+                    true,
+                )
             } else {
-                "wildcard match will also match any future added variants"
+                ("wildcard match will also match any future added variants", false)
             };
 
-            span_lint_and_sugg(
-                cx,
-                WILDCARD_ENUM_MATCH_ARM,
-                wildcard_span,
-                message,
-                "try",
-                suggestions.join(" | "),
-                Applicability::MaybeIncorrect,
-            );
+            span_lint_and_then(cx, WILDCARD_ENUM_MATCH_ARM, wildcard_span, message, |diag| {
+                let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
+                if add_wildcard {
+                    suggestions.push("_".into());
+                }
+                diag.span_suggestion(
+                    wildcard_span,
+                    "try",
+                    suggestions.join(" | "),
+                    Applicability::MaybeIncorrect,
+                );
+            });
         },
     };
 }
@@ -176,9 +180,8 @@ enum CommonPrefixSearcher<'a> {
 }
 impl<'a> CommonPrefixSearcher<'a> {
     fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
-        match path {
-            [path @ .., _] => self.with_prefix(path),
-            [] => (),
+        if let [path @ .., _] = path {
+            self.with_prefix(path);
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index 310675d01a2..d0d2025878e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note;
 use clippy_utils::macros::{is_panic, root_macro_call};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{in_constant, is_wild, peel_blocks_with_stmt};
+use clippy_utils::{is_in_const_context, is_wild, peel_blocks_with_stmt};
 use rustc_hir::{Arm, Expr, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::{kw, sym};
@@ -11,7 +11,7 @@ use super::MATCH_WILD_ERR_ARM;
 
 pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
     // `unwrap`/`expect` is not (yet) const, so we want to allow this in const contexts for now
-    if in_constant(cx, ex.hir_id) {
+    if is_in_const_context(cx) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index cec3504ed8d..cf5377e0725 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -27,7 +27,7 @@ mod wild_in_or_pats;
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
 use clippy_utils::source::walk_span_to_context;
-use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg};
+use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg};
 use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -1069,7 +1069,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     match_str_case_mismatch::check(cx, ex, arms);
                     redundant_guards::check(cx, arms, &self.msrv);
 
-                    if !in_constant(cx, expr.hir_id) {
+                    if !is_in_const_context(cx) {
                         manual_unwrap_or::check_match(cx, expr, ex, arms);
                         manual_map::check_match(cx, expr, ex, arms);
                         manual_filter::check_match(cx, ex, arms, expr);
@@ -1098,7 +1098,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                             else_expr,
                         );
                     }
-                    if !in_constant(cx, expr.hir_id) {
+                    if !is_in_const_context(cx) {
                         manual_unwrap_or::check_if_let(
                             cx,
                             expr,
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 45b375dbe3d..71f211be925 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt};
+use clippy_utils::consts::{mir_to_const, ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint_and_note;
 use core::cmp::Ordering;
 use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
@@ -33,22 +33,20 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
         .filter_map(|arm| {
             if let Arm { pat, guard: None, .. } = *arm {
                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
-                    let lhs_const = match lhs {
-                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
-                        None => {
-                            let min_val_const = ty.numeric_min_val(cx.tcx)?;
-                            mir_to_const(cx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
-                        },
+                    let lhs_const = if let Some(lhs) = lhs {
+                        ConstEvalCtxt::new(cx).eval(lhs)?
+                    } else {
+                        let min_val_const = ty.numeric_min_val(cx.tcx)?;
+                        mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
                     };
-                    let rhs_const = match rhs {
-                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
-                        None => {
-                            let max_val_const = ty.numeric_max_val(cx.tcx)?;
-                            mir_to_const(cx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
-                        },
+                    let rhs_const = if let Some(rhs) = rhs {
+                        ConstEvalCtxt::new(cx).eval(rhs)?
+                    } else {
+                        let max_val_const = ty.numeric_max_val(cx.tcx)?;
+                        mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
                     };
-                    let lhs_val = lhs_const.int_value(cx, ty)?;
-                    let rhs_val = rhs_const.int_value(cx, ty)?;
+                    let lhs_val = lhs_const.int_value(cx.tcx, ty)?;
+                    let rhs_val = rhs_const.int_value(cx.tcx, ty)?;
                     let rhs_bound = match range_end {
                         RangeEnd::Included => EndBound::Included(rhs_val),
                         RangeEnd::Excluded => EndBound::Excluded(rhs_val),
@@ -60,7 +58,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                 }
 
                 if let PatKind::Lit(value) = pat.kind {
-                    let value = constant_full_int(cx, cx.typeck_results(), value)?;
+                    let value = ConstEvalCtxt::new(cx).eval_full_int(value)?;
                     return Some(SpannedRange {
                         span: pat.span,
                         node: (value, EndBound::Included(value)),
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index c2c0fbf439d..8222c3057f7 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
-use clippy_utils::{in_constant, path_to_local};
+use clippy_utils::{is_in_const_context, path_to_local};
 use rustc_ast::{BorrowKind, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -116,7 +116,7 @@ fn check_method_calls<'tcx>(
         // `s if s.is_empty()` becomes ""
         // `arr if arr.is_empty()` becomes []
 
-        if ty.is_str() && !in_constant(cx, if_expr.hir_id) {
+        if ty.is_str() && !is_in_const_context(cx) {
             r#""""#.into()
         } else if slice_like {
             "[]".into()
diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
index 316b2f63e4e..2154cd5b24a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::{Pat, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
@@ -15,13 +15,15 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
         && fields.len() == def.non_enum_variant().fields.len()
         && !def.non_enum_variant().is_field_list_non_exhaustive()
     {
-        span_lint_and_help(
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
             cx,
             REST_PAT_IN_FULLY_BOUND_STRUCTS,
             pat.span,
             "unnecessary use of `..` pattern in struct binding. All fields were already bound",
-            None,
-            "consider removing `..` from this binding",
+            |diag| {
+                diag.help("consider removing `..` from this binding");
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 99fdbcff890..24dea03601c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -1,12 +1,17 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{expr_block, snippet, SpanRangeExt};
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs};
-use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
-use core::cmp::max;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{
+    is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs,
+};
+use core::ops::ControlFlow;
+use rustc_arena::DroplessArena;
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingMode, Block, Expr, ExprKind, Pat, PatKind};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit::{walk_pat, Visitor};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind, QPath};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef};
 use rustc_span::{sym, Span};
 
 use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
@@ -27,52 +32,58 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
 }
 
 #[rustfmt::skip]
-pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
-    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
-        if expr.span.from_expansion() {
-            // Don't lint match expressions present in
-            // macro_rules! block
-            return;
-        }
-        if let PatKind::Or(..) = arms[0].pat.kind {
-            // don't lint for or patterns for now, this makes
-            // the lint noisy in unnecessary situations
-            return;
-        }
-        let els = arms[1].body;
-        let els = if is_unit_expr(peel_blocks(els)) && !empty_arm_has_comment(cx, els.span) {
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>], expr: &'tcx Expr<'_>) {
+    if let [arm1, arm2] = arms
+        && arm1.guard.is_none()
+        && arm2.guard.is_none()
+        && !expr.span.from_expansion()
+        // don't lint for or patterns for now, this makes
+        // the lint noisy in unnecessary situations
+        && !matches!(arm1.pat.kind, PatKind::Or(..))
+    {
+        let els = if is_unit_expr(peel_blocks(arm2.body)) && !empty_arm_has_comment(cx, arm2.body.span) {
             None
-        } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
-            if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
+        } else if let ExprKind::Block(block, _) = arm2.body.kind {
+            if matches!((block.stmts, block.expr), ([], Some(_)) | ([_], None)) {
                 // single statement/expr "else" block, don't lint
                 return;
             }
             // block with 2+ statements or 1 expr and 1+ statement
-            Some(els)
+            Some(arm2.body)
         } else {
             // not a block or an empty block w/ comments, don't lint
             return;
         };
 
-        let ty = cx.typeck_results().expr_ty(ex);
-        if (*ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id)) &&
-            (check_single_pattern(arms) || check_opt_like(cx, arms, ty)) {
-            report_single_pattern(cx, ex, arms, expr, els);
+        let typeck = cx.typeck_results();
+        if *typeck.expr_ty(ex).peel_refs().kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
+            let mut v = PatVisitor {
+                typeck,
+                has_enum: false,
+            };
+            if v.visit_pat(arm2.pat).is_break() {
+                return;
+            }
+            if v.has_enum {
+                let cx = PatCtxt {
+                    tcx: cx.tcx,
+                    param_env: cx.param_env,
+                    typeck,
+                    arena: DroplessArena::default(),
+                };
+                let mut state = PatState::Other;
+                if !(state.add_pat(&cx, arm2.pat) || state.add_pat(&cx, arm1.pat)) {
+                    // Don't lint if the pattern contains an enum which doesn't have a wild match.
+                    return;
+                }
+            }
+
+            report_single_pattern(cx, ex, arm1, expr, els);
         }
     }
 }
 
-fn check_single_pattern(arms: &[Arm<'_>]) -> bool {
-    is_wild(arms[1].pat)
-}
-
-fn report_single_pattern(
-    cx: &LateContext<'_>,
-    ex: &Expr<'_>,
-    arms: &[Arm<'_>],
-    expr: &Expr<'_>,
-    els: Option<&Expr<'_>>,
-) {
+fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, expr: &Expr<'_>, els: Option<&Expr<'_>>) {
     let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
     let ctxt = expr.span.ctxt();
     let mut app = Applicability::MachineApplicable;
@@ -80,9 +91,9 @@ fn report_single_pattern(
         format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app))
     });
 
-    let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
+    let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
     let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind
-        && let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex))
+        && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
         && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
         && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
         && (ty.is_integral()
@@ -114,17 +125,17 @@ fn report_single_pattern(
             snippet(cx, ex.span, ".."),
             // PartialEq for different reference counts may not exist.
             "&".repeat(ref_count_diff),
-            snippet(cx, arms[0].pat.span, ".."),
-            expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
+            snippet(cx, arm.pat.span, ".."),
+            expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app),
         );
         (msg, sugg)
     } else {
         let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
         let sugg = format!(
             "if let {} = {} {}{els_str}",
-            snippet(cx, arms[0].pat.span, ".."),
+            snippet(cx, arm.pat.span, ".."),
             snippet(cx, ex.span, ".."),
-            expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
+            expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app),
         );
         (msg, sugg)
     };
@@ -132,106 +143,227 @@ fn report_single_pattern(
     span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app);
 }
 
-fn check_opt_like<'a>(cx: &LateContext<'a>, arms: &[Arm<'_>], ty: Ty<'a>) -> bool {
-    // We don't want to lint if the second arm contains an enum which could
-    // have more variants in the future.
-    form_exhaustive_matches(cx, ty, arms[0].pat, arms[1].pat)
+struct PatVisitor<'tcx> {
+    typeck: &'tcx TypeckResults<'tcx>,
+    has_enum: bool,
 }
-
-/// Returns `true` if all of the types in the pattern are enums which we know
-/// won't be expanded in the future
-fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) -> bool {
-    let mut paths_and_types = Vec::new();
-    collect_pat_paths(&mut paths_and_types, cx, pat, ty);
-    paths_and_types.iter().all(|ty| in_candidate_enum(cx, *ty))
+impl<'tcx> Visitor<'tcx> for PatVisitor<'tcx> {
+    type Result = ControlFlow<()>;
+    fn visit_pat(&mut self, pat: &'tcx Pat<'_>) -> Self::Result {
+        if matches!(pat.kind, PatKind::Binding(..)) {
+            ControlFlow::Break(())
+        } else {
+            self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().map_or(false, AdtDef::is_enum);
+            walk_pat(self, pat)
+        }
+    }
 }
 
-/// Returns `true` if the given type is an enum we know won't be expanded in the future
-fn in_candidate_enum(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    // list of candidate `Enum`s we know will never get any more members
-    let candidates = [sym::Cow, sym::Option, sym::Result];
+/// The context needed to manipulate a `PatState`.
+struct PatCtxt<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    typeck: &'tcx TypeckResults<'tcx>,
+    arena: DroplessArena,
+}
 
-    for candidate_ty in candidates {
-        if is_type_diagnostic_item(cx, ty, candidate_ty) {
-            return true;
+/// State for tracking whether a match can become non-exhaustive by adding a variant to a contained
+/// enum.
+///
+/// This treats certain std enums as if they will never be extended.
+enum PatState<'a> {
+    /// Either a wild match or an uninteresting type. Uninteresting types include:
+    /// * builtin types (e.g. `i32` or `!`)
+    /// * A struct/tuple/array containing only uninteresting types.
+    /// * A std enum containing only uninteresting types.
+    Wild,
+    /// A std enum we know won't be extended. Tracks the states of each variant separately.
+    ///
+    /// This is not used for `Option` since it uses the current pattern to track it's state.
+    StdEnum(&'a mut [PatState<'a>]),
+    /// Either the initial state for a pattern or a non-std enum. There is currently no need to
+    /// distinguish these cases.
+    ///
+    /// For non-std enums there's no need to track the state of sub-patterns as the state of just
+    /// this pattern on it's own is enough for linting. Consider two cases:
+    /// * This enum has no wild match. This case alone is enough to determine we can lint.
+    /// * This enum has a wild match and therefore all sub-patterns also have a wild match.
+    ///
+    /// In both cases the sub patterns are not needed to determine whether to lint.
+    Other,
+}
+impl<'a> PatState<'a> {
+    /// Adds a set of patterns as a product type to the current state. Returns whether or not the
+    /// current state is a wild match after the merge.
+    fn add_product_pat<'tcx>(
+        &mut self,
+        cx: &'a PatCtxt<'tcx>,
+        pats: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
+    ) -> bool {
+        // Ideally this would actually keep track of the state separately for each pattern. Doing so would
+        // require implementing something similar to exhaustiveness checking which is a significant increase
+        // in complexity.
+        //
+        // For now treat this as a wild match only if all the sub-patterns are wild
+        let is_wild = pats.into_iter().all(|p| {
+            let mut state = Self::Other;
+            state.add_pat(cx, p)
+        });
+        if is_wild {
+            *self = Self::Wild;
         }
+        is_wild
     }
-    false
-}
 
-/// Collects types from the given pattern
-fn collect_pat_paths<'a>(acc: &mut Vec<Ty<'a>>, cx: &LateContext<'a>, pat: &Pat<'_>, ty: Ty<'a>) {
-    match pat.kind {
-        PatKind::Tuple(inner, _) => inner.iter().for_each(|p| {
-            let p_ty = cx.typeck_results().pat_ty(p);
-            collect_pat_paths(acc, cx, p, p_ty);
-        }),
-        PatKind::TupleStruct(..) | PatKind::Binding(BindingMode::NONE, .., None) | PatKind::Path(_) => {
-            acc.push(ty);
-        },
-        _ => {},
+    /// Attempts to get the state for the enum variant, initializing the current state if necessary.
+    fn get_std_enum_variant<'tcx>(
+        &mut self,
+        cx: &'a PatCtxt<'tcx>,
+        adt: AdtDef<'tcx>,
+        path: &'tcx QPath<'_>,
+        hir_id: HirId,
+    ) -> Option<(&mut Self, &'tcx VariantDef)> {
+        let states = match self {
+            Self::Wild => return None,
+            Self::Other => {
+                *self = Self::StdEnum(cx.arena.alloc_from_iter((0..adt.variants().len()).map(|_| Self::Other)));
+                let Self::StdEnum(x) = self else {
+                    unreachable!();
+                };
+                x
+            },
+            Self::StdEnum(x) => x,
+        };
+        let i = match cx.typeck.qpath_res(path, hir_id) {
+            Res::Def(DefKind::Ctor(..), id) => adt.variant_index_with_ctor_id(id),
+            Res::Def(DefKind::Variant, id) => adt.variant_index_with_id(id),
+            _ => return None,
+        };
+        Some((&mut states[i.as_usize()], adt.variant(i)))
     }
-}
 
-/// Returns true if the given arm of pattern matching contains wildcard patterns.
-fn contains_only_wilds(pat: &Pat<'_>) -> bool {
-    match pat.kind {
-        PatKind::Wild => true,
-        PatKind::Tuple(inner, _) | PatKind::TupleStruct(_, inner, ..) => inner.iter().all(contains_only_wilds),
-        _ => false,
+    fn check_all_wild_enum(&mut self) -> bool {
+        if let Self::StdEnum(states) = self
+            && states.iter().all(|s| matches!(s, Self::Wild))
+        {
+            *self = Self::Wild;
+            true
+        } else {
+            false
+        }
     }
-}
 
-/// Returns true if the given patterns forms only exhaustive matches that don't contain enum
-/// patterns without a wildcard.
-fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, right: &Pat<'_>) -> bool {
-    match (&left.kind, &right.kind) {
-        (PatKind::Wild, _) | (_, PatKind::Wild) => true,
-        (PatKind::Tuple(left_in, left_pos), PatKind::Tuple(right_in, right_pos)) => {
-            // We don't actually know the position and the presence of the `..` (dotdot) operator
-            // in the arms, so we need to evaluate the correct offsets here in order to iterate in
-            // both arms at the same time.
-            let left_pos = left_pos.as_opt_usize();
-            let right_pos = right_pos.as_opt_usize();
-            let len = max(
-                left_in.len() + usize::from(left_pos.is_some()),
-                right_in.len() + usize::from(right_pos.is_some()),
-            );
-            let mut left_pos = left_pos.unwrap_or(usize::MAX);
-            let mut right_pos = right_pos.unwrap_or(usize::MAX);
-            let mut left_dot_space = 0;
-            let mut right_dot_space = 0;
-            for i in 0..len {
-                let mut found_dotdot = false;
-                if i == left_pos {
-                    left_dot_space += 1;
-                    if left_dot_space < len - left_in.len() {
-                        left_pos += 1;
-                    }
-                    found_dotdot = true;
-                }
-                if i == right_pos {
-                    right_dot_space += 1;
-                    if right_dot_space < len - right_in.len() {
-                        right_pos += 1;
-                    }
-                    found_dotdot = true;
-                }
-                if found_dotdot {
-                    continue;
+    #[expect(clippy::similar_names)]
+    fn add_struct_pats<'tcx>(
+        &mut self,
+        cx: &'a PatCtxt<'tcx>,
+        pat: &'tcx Pat<'tcx>,
+        path: &'tcx QPath<'tcx>,
+        single_pat: Option<&'tcx Pat<'tcx>>,
+        pats: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
+    ) -> bool {
+        let ty::Adt(adt, _) = *cx.typeck.pat_ty(pat).kind() else {
+            // Should never happen
+            *self = Self::Wild;
+            return true;
+        };
+        if adt.is_struct() {
+            return if let Some(pat) = single_pat
+                && adt.non_enum_variant().fields.len() == 1
+            {
+                self.add_pat(cx, pat)
+            } else {
+                self.add_product_pat(cx, pats)
+            };
+        }
+        match cx.tcx.get_diagnostic_name(adt.did()) {
+            Some(sym::Option) => {
+                if let Some(pat) = single_pat {
+                    self.add_pat(cx, pat)
+                } else {
+                    *self = Self::Wild;
+                    true
                 }
-                if !contains_only_wilds(&left_in[i - left_dot_space])
-                    && !contains_only_wilds(&right_in[i - right_dot_space])
+            },
+            Some(sym::Result | sym::Cow) => {
+                let Some((state, variant)) = self.get_std_enum_variant(cx, adt, path, pat.hir_id) else {
+                    return matches!(self, Self::Wild);
+                };
+                let is_wild = if let Some(pat) = single_pat
+                    && variant.fields.len() == 1
                 {
-                    return false;
-                }
-            }
-            true
-        },
-        (PatKind::TupleStruct(..), PatKind::Path(_)) => pat_in_candidate_enum(cx, ty, right),
-        (PatKind::TupleStruct(..), PatKind::TupleStruct(_, inner, _)) => {
-            pat_in_candidate_enum(cx, ty, right) && inner.iter().all(contains_only_wilds)
-        },
-        _ => false,
+                    state.add_pat(cx, pat)
+                } else {
+                    state.add_product_pat(cx, pats)
+                };
+                is_wild && self.check_all_wild_enum()
+            },
+            _ => matches!(self, Self::Wild),
+        }
+    }
+
+    /// Adds the pattern into the current state. Returns whether or not the current state is a wild
+    /// match after the merge.
+    #[expect(clippy::similar_names)]
+    fn add_pat<'tcx>(&mut self, cx: &'a PatCtxt<'tcx>, pat: &'tcx Pat<'_>) -> bool {
+        match pat.kind {
+            PatKind::Path(_)
+                if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
+                    ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
+                    ty::Tuple(tys) => !tys.is_empty(),
+                    ty::Array(_, len) => len.try_eval_target_usize(cx.tcx, cx.param_env) != Some(1),
+                    ty::Slice(..) => true,
+                    _ => false,
+                } =>
+            {
+                matches!(self, Self::Wild)
+            },
+
+            // Patterns for things which can only contain a single sub-pattern.
+            PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
+                self.add_pat(cx, pat)
+            },
+            PatKind::Tuple([sub_pat], pos)
+                if pos.as_opt_usize().is_none() || cx.typeck.pat_ty(pat).tuple_fields().len() == 1 =>
+            {
+                self.add_pat(cx, sub_pat)
+            },
+            PatKind::Slice([sub_pat], _, []) | PatKind::Slice([], _, [sub_pat])
+                if let ty::Array(_, len) = *cx.typeck.pat_ty(pat).kind()
+                    && len.try_eval_target_usize(cx.tcx, cx.param_env) == Some(1) =>
+            {
+                self.add_pat(cx, sub_pat)
+            },
+
+            PatKind::Or(pats) => pats.iter().any(|p| self.add_pat(cx, p)),
+            PatKind::Tuple(pats, _) => self.add_product_pat(cx, pats),
+            PatKind::Slice(head, _, tail) => self.add_product_pat(cx, head.iter().chain(tail)),
+
+            PatKind::TupleStruct(ref path, pats, _) => self.add_struct_pats(
+                cx,
+                pat,
+                path,
+                if let [pat] = pats { Some(pat) } else { None },
+                pats.iter(),
+            ),
+            PatKind::Struct(ref path, pats, _) => self.add_struct_pats(
+                cx,
+                pat,
+                path,
+                if let [pat] = pats { Some(pat.pat) } else { None },
+                pats.iter().map(|p| p.pat),
+            ),
+
+            PatKind::Wild
+            | PatKind::Binding(_, _, _, None)
+            | PatKind::Lit(_)
+            | PatKind::Range(..)
+            | PatKind::Path(_)
+            | PatKind::Never
+            | PatKind::Err(_) => {
+                *self = PatState::Wild;
+                true
+            },
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
index dd489fc250b..b7ffa8b8a78 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res};
@@ -48,29 +48,28 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
             return;
         };
 
-        let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
-        let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
-        let mut applicability = Applicability::MachineApplicable;
-        let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
-        let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
-            "" // already returns
-        } else {
-            "return "
-        };
-        let suggestion = if err_ty == expr_err_ty {
-            format!("{ret_prefix}{prefix}{origin_snippet}{suffix}")
-        } else {
-            format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}")
-        };
-
-        span_lint_and_sugg(
+        span_lint_and_then(
             cx,
             TRY_ERR,
             expr.span,
             "returning an `Err(_)` with the `?` operator",
-            "try",
-            suggestion,
-            applicability,
+            |diag| {
+                let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
+                let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
+                let mut applicability = Applicability::MachineApplicable;
+                let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
+                let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
+                    "" // already returns
+                } else {
+                    "return "
+                };
+                let suggestion = if err_ty == expr_err_ty {
+                    format!("{ret_prefix}{prefix}{origin_snippet}{suffix}")
+                } else {
+                    format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}")
+                };
+                diag.span_suggestion(expr.span, "try", suggestion, applicability);
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 20f3722e173..2a8a5fcc3b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -1,5 +1,5 @@
 use super::{contains_return, BIND_INSTEAD_OF_MAP};
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::peel_blocks;
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::visitors::find_all_ret_expressions;
@@ -136,15 +136,16 @@ impl BindInsteadOfMap {
             return false;
         };
         span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "try",
+            diag.multipart_suggestion(
+                format!("use `{}` instead", self.good_method_name),
+                std::iter::once((span, self.good_method_name.into()))
+                    .chain(
+                        suggs
+                            .into_iter()
+                            .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
+                    )
+                    .collect(),
                 Applicability::MachineApplicable,
-                std::iter::once((span, self.good_method_name.into())).chain(
-                    suggs
-                        .into_iter()
-                        .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
-                ),
             );
         });
         true
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 926bd06bacb..e0826b53004 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -29,19 +29,22 @@ pub(super) fn check(
             sym::RcWeak | sym::ArcWeak => "Weak",
             _ => return,
         };
-
-        // Sometimes unnecessary ::<_> after Rc/Arc/Weak
-        let mut app = Applicability::Unspecified;
-        let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
-
-        span_lint_and_sugg(
+        span_lint_and_then(
             cx,
             CLONE_ON_REF_PTR,
             expr.span,
             "using `.clone()` on a ref-counted pointer",
-            "try",
-            format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
-            app,
+            |diag| {
+                // Sometimes unnecessary ::<_> after Rc/Arc/Weak
+                let mut app = Applicability::Unspecified;
+                let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
+                diag.span_suggestion(
+                    expr.span,
+                    "try",
+                    format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
+                    app,
+                );
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
index eab536b88a5..2ab0401947c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir as hir;
@@ -33,6 +33,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         span = expr.span;
     }
     let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files");
-    let help_msg = format!("use `{help_unary}FileType::is_dir()` instead");
-    span_lint_and_help(cx, FILETYPE_IS_FILE, span, lint_msg, None, help_msg);
+
+    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+    span_lint_and_then(cx, FILETYPE_IS_FILE, span, lint_msg, |diag| {
+        diag.help(format!("use `{help_unary}FileType::is_dir()` instead"));
+    });
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
index 455274a4428..c6285c87a26 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
@@ -1,5 +1,5 @@
 use super::utils::derefs_to_slice;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -19,9 +19,7 @@ pub(super) fn check<'tcx>(
 ) {
     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
     // because they do not implement `IndexMut`
-    let mut applicability = Applicability::MachineApplicable;
     let expr_ty = cx.typeck_results().expr_ty(recv);
-    let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
     let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() {
         "slice"
     } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) {
@@ -58,24 +56,34 @@ pub(super) fn check<'tcx>(
     };
 
     let mut_str = if is_mut { "_mut" } else { "" };
-    let borrow_str = if !needs_ref {
-        ""
-    } else if is_mut {
-        "&mut "
-    } else {
-        "&"
-    };
 
-    span_lint_and_sugg(
+    span_lint_and_then(
         cx,
         GET_UNWRAP,
         span,
-        format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"),
-        "try",
-        format!(
-            "{borrow_str}{}[{get_args_str}]",
-            snippet_with_applicability(cx, recv.span, "..", &mut applicability)
-        ),
-        applicability,
+        format!("called `.get{mut_str}().unwrap()` on a {caller_type}"),
+        |diag| {
+            let mut applicability = Applicability::MachineApplicable;
+            let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
+
+            let borrow_str = if !needs_ref {
+                ""
+            } else if is_mut {
+                "&mut "
+            } else {
+                "&"
+            };
+
+            diag.span_suggestion_with_style(
+                span,
+                "using `[]` is clearer and more concise",
+                format!(
+                    "{borrow_str}{}[{get_args_str}]",
+                    snippet_with_applicability(cx, recv.span, "..", &mut applicability)
+                ),
+                applicability,
+                rustc_errors::SuggestionStyle::ShowAlways,
+            );
+        },
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index c510cd915d0..519091406cc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
-use clippy_utils::{is_diag_item_method, is_diag_trait_item};
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -14,7 +14,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
         && is_clone_like(cx, method_name, method_def_id)
         && let return_type = cx.typeck_results().expr_ty(expr)
         && let input_type = cx.typeck_results().expr_ty(recv)
-        && let (input_type, ref_count) = peel_mid_ty_refs(input_type)
+        && let (input_type, ref_count) = peel_middle_ty_refs(input_type)
         && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned))
         && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()))
         && return_type == input_type
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
index 210e4ae0a7b..22d896433f0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -2,7 +2,7 @@
 
 use super::IS_DIGIT_ASCII_RADIX;
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::consts::{constant_full_int, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    if let Some(radix_val) = constant_full_int(cx, cx.typeck_results(), radix) {
+    if let Some(radix_val) = ConstEvalCtxt::new(cx).eval_full_int(radix) {
         let (num, replacement) = match radix_val {
             FullInt::S(10) | FullInt::U(10) => (10, "is_ascii_digit"),
             FullInt::S(16) | FullInt::U(16) => (16, "is_ascii_hexdigit"),
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
index d921b7ea14f..cc82f6cfd63 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::constant_is_empty;
+use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{find_binding_init, path_to_local};
 use rustc_hir::{Expr, HirId};
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_
     if !receiver.span.eq_ctxt(init_expr.span) {
         return;
     }
-    if let Some(init_is_empty) = constant_is_empty(cx, init_expr) {
+    if let Some(init_is_empty) = ConstEvalCtxt::new(cx).eval_is_empty(init_expr) {
         span_lint(
             cx,
             CONST_IS_EMPTY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 05e77386128..33de3b87abc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -1,15 +1,12 @@
-#![allow(unused_imports)]
-
 use super::ITER_KV_MAP;
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_with_applicability};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::pat_is_wild;
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{pat_is_wild, sugg};
-use rustc_hir::{BindingMode, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
-use rustc_lint::{LateContext, LintContext};
-use rustc_middle::ty;
-use rustc_span::{sym, Span};
+use rustc_hir::{Body, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
 
 /// lint use of:
 ///
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
index 262a57ab591..9ff6eaa3487 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_lang_item_or_ctor, is_trait_method};
@@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     if let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id))
         && let def_id = item.owner_id.to_def_id()
         && is_trait_method(cx, expr, sym::Iterator)
-        && let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg)
+        && let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg)
         && !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext)
     {
         let mut app = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
index 6b696b42a69..39e440e784f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{is_from_proc_macro, is_trait_method};
 use rustc_errors::Applicability;
@@ -11,7 +11,7 @@ use super::ITER_SKIP_ZERO;
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) {
     if !expr.span.from_expansion()
         && is_trait_method(cx, expr, sym::Iterator)
-        && let Some(arg) = constant(cx, cx.typeck_results(), arg_expr).and_then(|constant| {
+        && let Some(arg) = ConstEvalCtxt::new(cx).eval(arg_expr).and_then(|constant| {
             if let Constant::Int(arg) = constant {
                 Some(arg)
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
index b631cd00cda..9b358235a40 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_trait_method;
 use rustc_hir as hir;
@@ -9,7 +9,7 @@ use super::ITERATOR_STEP_BY_ZERO;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) {
+        if let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg) {
             span_lint(
                 cx,
                 ITERATOR_STEP_BY_ZERO,
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index a5ba5e5d891..08ce7e204dd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -2,10 +2,10 @@ use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function};
-use clippy_utils::{is_diag_trait_item, match_def_path, paths, peel_blocks};
+use clippy_utils::{is_diag_trait_item, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, LangItem};
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty;
@@ -114,7 +114,7 @@ fn handle_path(
     recv: &hir::Expr<'_>,
 ) {
     if let Some(path_def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id()
-        && match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD)
+        && cx.tcx.lang_items().get(LangItem::CloneFn) == Some(path_def_id)
     {
         // The `copied` and `cloned` methods are only available on `&T` and `&mut T` in `Option`
         // and `Result`.
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
index fbb83c8ce56..162f0ac564d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
 use rustc_lint::LateContext;
@@ -22,13 +22,17 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
     {
         // span the area of the closure capture and warn that the
         // original error will be thrown away
-        span_lint_and_help(
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
             cx,
             MAP_ERR_IGNORE,
             fn_decl_span,
             "`map_err(|_|...` wildcard pattern discards the original error",
-            None,
-            "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
+            |diag| {
+                diag.help(
+                    "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
+                );
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index aa4cad9342a..1d7b10fe8f0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -133,7 +133,7 @@ mod zst_offset;
 
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
@@ -749,7 +749,6 @@ declare_clippy_lint! {
     ///
      /// ### Example
     /// ```no_run
-    /// # #![allow(unused)]
     /// (0_i32..10)
     ///     .filter(|n| n.checked_add(1).is_some())
     ///     .map(|n| n.checked_add(1).unwrap());
@@ -757,7 +756,6 @@ declare_clippy_lint! {
     ///
     /// Use instead:
     /// ```no_run
-    /// # #[allow(unused)]
     /// (0_i32..10).filter_map(|n| n.checked_add(1));
     /// ```
     #[clippy::version = "1.51.0"]
@@ -850,7 +848,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #![allow(unused)]
     /// let vec = vec![1];
     /// vec.iter().find(|x| **x == 0).is_some();
     ///
@@ -862,7 +859,6 @@ declare_clippy_lint! {
     /// let vec = vec![1];
     /// vec.iter().any(|x| *x == 0);
     ///
-    /// # #[allow(unused)]
     /// !"hello world".contains("world");
     /// ```
     #[clippy::version = "pre 1.29.0"]
@@ -1505,7 +1501,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #[allow(unused)]
     /// (0..3).fold(false, |acc, x| acc || x > 2);
     /// ```
     ///
@@ -1897,7 +1892,9 @@ declare_clippy_lint! {
     /// trait.
     ///
     /// ### Why is this bad?
-    /// It is recommended style to use collect. See
+    /// If it's needed to create a collection from the contents of an iterator, the `Iterator::collect(_)`
+    /// method is preferred. However, when it's needed to specify the container type,
+    /// `Vec::from_iter(_)` can be more readable than using a turbofish (e.g. `_.collect::<Vec<_>>()`). See
     /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
     ///
     /// ### Example
@@ -1916,6 +1913,14 @@ declare_clippy_lint! {
     ///
     /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
     /// ```
+    /// but prefer to use
+    /// ```no_run
+    /// let numbers: Vec<i32> = FromIterator::from_iter(1..=5);
+    /// ```
+    /// instead of
+    /// ```no_run
+    /// let numbers = (1..=5).collect::<Vec<_>>();
+    /// ```
     #[clippy::version = "1.49.0"]
     pub FROM_ITER_INSTEAD_OF_COLLECT,
     pedantic,
@@ -2008,13 +2013,11 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #[allow(unused)]
     /// "Hello".bytes().nth(3);
     /// ```
     ///
     /// Use instead:
     /// ```no_run
-    /// # #[allow(unused)]
     /// "Hello".as_bytes().get(3);
     /// ```
     #[clippy::version = "1.52.0"]
@@ -2059,7 +2062,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #![allow(unused)]
     /// let some_vec = vec![0, 1, 2, 3];
     ///
     /// some_vec.iter().count();
@@ -3656,7 +3658,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #![allow(unused)]
     /// let owned_string = "This is a string".to_owned();
     /// owned_string.as_str().as_bytes()
     /// # ;
@@ -3664,7 +3665,6 @@ declare_clippy_lint! {
     ///
     /// Use instead:
     /// ```no_run
-    /// # #![allow(unused)]
     /// let owned_string = "This is a string".to_owned();
     /// owned_string.as_bytes()
     /// # ;
@@ -4915,13 +4915,13 @@ impl Methods {
                     str_split::check(cx, expr, recv, arg);
                 },
                 ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
-                    if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
+                    if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                         str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
                     }
                 },
                 ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
-                    if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
+                    if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index d425b505a76..cbeb48b6cc3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -151,7 +151,7 @@ fn check_open_options(cx: &LateContext<'_>, settings: &[(OpenOption, Argument, S
                 cx,
                 NONSENSICAL_OPEN_OPTIONS,
                 prev_span,
-                format!("the method `{}` is called more than once", &option),
+                format!("the method `{option}` is called more than once"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
index bb4cdd2a6fa..7837517ed5d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_lang_item;
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
     recv: &'tcx Expr<'_>,
     repeat_arg: &'tcx Expr<'_>,
 ) {
-    if constant(cx, cx.typeck_results(), repeat_arg) == Some(Constant::Int(1)) {
+    if ConstEvalCtxt::new(cx).eval(repeat_arg) == Some(Constant::Int(1)) {
         let ty = cx.typeck_results().expr_ty(recv).peel_refs();
         if ty.is_str() {
             span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 4f42fb73547..12cabd43cb1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -1,5 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::usage::local_used_after_expr;
@@ -301,7 +301,7 @@ fn parse_iter_usage<'tcx>(
                     };
                 },
                 ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
-                    if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) {
+                    if let Some(Constant::Int(idx)) = ConstEvalCtxt::new(cx).eval(idx_expr) {
                         let span = if name.ident.as_str() == "nth" {
                             e.span
                         } else if let Some((_, Node::Expr(next_expr))) = iter.next()
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
index 78851d4122f..86c0a6322b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
@@ -3,7 +3,7 @@ use std::cmp::Ordering;
 use super::UNNECESSARY_MIN_OR_MAX;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 
-use clippy_utils::consts::{constant, constant_with_source, Constant, ConstantSource, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt};
 use clippy_utils::source::snippet;
 
 use rustc_errors::Applicability;
@@ -20,10 +20,9 @@ pub(super) fn check<'tcx>(
     arg: &'tcx Expr<'_>,
 ) {
     let typeck_results = cx.typeck_results();
-    if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) =
-        constant_with_source(cx, typeck_results, recv)
-        && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) =
-            constant_with_source(cx, typeck_results, arg)
+    let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results);
+    if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv)
+        && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg)
     {
         let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else {
             return;
@@ -78,9 +77,9 @@ enum Extrema {
 fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Extrema> {
     let ty = cx.typeck_results().expr_ty(expr);
 
-    let cv = constant(cx, cx.typeck_results(), expr)?;
+    let cv = ConstEvalCtxt::new(cx).eval(expr)?;
 
-    match (cv.int_value(cx, ty)?, ty.kind()) {
+    match (cv.int_value(cx.tcx, ty)?, ty.kind()) {
         (FullInt::S(i), &ty::Int(ity)) if i == i128::MIN >> (128 - ity.bit_width()?) => Some(Extrema::Minimum),
         (FullInt::S(i), &ty::Int(ity)) if i == i128::MAX >> (128 - ity.bit_width()?) => Some(Extrema::Maximum),
         (FullInt::U(i), &ty::Uint(uty)) if i == u128::MAX >> (128 - uty.bit_width()?) => Some(Extrema::Maximum),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 5d899415d77..fed2b128dcf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -3,12 +3,11 @@ use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_opt};
-use clippy_utils::ty::{
-    get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs,
-};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::find_all_ret_expressions;
 use clippy_utils::{
-    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty,
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, peel_middle_ty_refs,
+    return_ty,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -120,8 +119,8 @@ fn check_addr_of_expr(
                 },
             ] = adjustments[..]
         && let receiver_ty = cx.typeck_results().expr_ty(receiver)
-        && let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty)
-        && let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty)
+        && let (target_ty, n_target_refs) = peel_middle_ty_refs(*target_ty)
+        && let (receiver_ty, n_receiver_refs) = peel_middle_ty_refs(receiver_ty)
         // Only flag cases satisfying at least one of the following three conditions:
         // * the referent and receiver types are distinct
         // * the referent/receiver type is a copyable array
@@ -382,7 +381,7 @@ fn check_other_call_arg<'tcx>(
         && let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder()
         && let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id)
         && let Some(input) = fn_sig.inputs().get(i)
-        && let (input, n_refs) = peel_mid_ty_refs(*input)
+        && let (input, n_refs) = peel_middle_ty_refs(*input)
         && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input)
         && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait()
         && let [trait_predicate] = trait_predicates
diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
index 8b8a965b9f0..3004d9c4233 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_hir_and_then};
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild};
 use rustc_errors::Applicability;
@@ -97,10 +97,8 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
             enumerate_span,
             "you seem to use `.enumerate()` and immediately discard the index",
             |diag| {
-                multispan_sugg_with_applicability(
-                    diag,
+                diag.multipart_suggestion(
                     "remove the `.enumerate()` call",
-                    Applicability::MachineApplicable,
                     vec![
                         (closure_param.span, new_closure_param),
                         (
@@ -108,6 +106,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
                             String::new(),
                         ),
                     ],
+                    Applicability::MachineApplicable,
                 );
             },
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index ae2b6e6347e..ebad4ae6ee9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -2,10 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{should_call_clone_as_function, walk_ptrs_ty_depth};
 use clippy_utils::{
-    get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, paths, peel_blocks, strip_pat_refs,
+    get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, peel_blocks, strip_pat_refs,
 };
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, LangItem};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
@@ -104,7 +104,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
 fn check_qpath(cx: &LateContext<'_>, qpath: hir::QPath<'_>, hir_id: hir::HirId) -> bool {
     // We check it's calling the `clone` method of the `Clone` trait.
     if let Some(path_def_id) = cx.qpath_res(&qpath, hir_id).opt_def_id() {
-        match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD)
+        cx.tcx.lang_items().get(LangItem::CloneFn) == Some(path_def_id)
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
index 181b413a182..8ed61637eca 100644
--- a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_trait_method;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir::{Expr, ExprKind, QPath};
@@ -23,6 +23,9 @@ pub(super) fn check<'tcx>(
         && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _)))
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File)
     {
-        span_lint_and_help(cx, VERBOSE_FILE_READS, expr.span, msg, None, help);
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, VERBOSE_FILE_READS, expr.span, msg, |diag| {
+            diag.help(help);
+        });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 28068c63473..7384e534ed7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -127,7 +127,7 @@ pub(super) fn check<'tcx>(
                         .collect::<Vec<_>>()
                         .join(" and ");
 
-                    format!("methods with the following characteristics: ({})", &s)
+                    format!("methods with the following characteristics: ({s})")
                 } else {
                     format!("methods called {}", &conventions[0])
                 }
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index c3fbca1d560..e95864c6db8 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_trait_method;
 use rustc_hir::{Expr, ExprKind};
@@ -106,15 +106,11 @@ fn fetch_const<'a, 'tcx>(
     if args.next().is_some() {
         return None;
     }
-    constant_simple(cx, cx.typeck_results(), first_arg).map_or_else(
-        || constant_simple(cx, cx.typeck_results(), second_arg).map(|c| (m, c, first_arg)),
-        |c| {
-            if constant_simple(cx, cx.typeck_results(), second_arg).is_none() {
-                // otherwise ignore
-                Some((m, c, second_arg))
-            } else {
-                None
-            }
-        },
-    )
+    let ecx = ConstEvalCtxt::new(cx);
+    match (ecx.eval_simple(first_arg), ecx.eval_simple(second_arg)) {
+        (Some(c), None) => Some((m, c, second_arg)),
+        (None, Some(c)) => Some((m, c, first_arg)),
+        // otherwise ignore
+        _ => None,
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
index e0a5e401a50..22467999cd8 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_lint::EarlyContext;
 use rustc_span::Span;
@@ -12,24 +12,36 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi
     // Do not lint when literal is unsuffixed.
     if !suffix.is_empty() {
         if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
-            span_lint_and_sugg(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 SEPARATED_LITERAL_SUFFIX,
                 lit_span,
                 format!("{sugg_type} type suffix should not be separated by an underscore"),
-                "remove the underscore",
-                format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
-                Applicability::MachineApplicable,
+                |diag| {
+                    diag.span_suggestion(
+                        lit_span,
+                        "remove the underscore",
+                        format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
+                        Applicability::MachineApplicable,
+                    );
+                },
             );
         } else {
-            span_lint_and_sugg(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 UNSEPARATED_LITERAL_SUFFIX,
                 lit_span,
                 format!("{sugg_type} type suffix should be separated by an underscore"),
-                "add an underscore",
-                format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),
-                Applicability::MachineApplicable,
+                |diag| {
+                    diag.span_suggestion(
+                        lit_span,
+                        "add an underscore",
+                        format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),
+                        Applicability::MachineApplicable,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
index cb305cf5582..6db03adf44a 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{Pat, PatKind};
 use rustc_lint::EarlyContext;
@@ -21,13 +21,15 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
             }
         }
         if !pfields.is_empty() && wilds == pfields.len() {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 UNNEEDED_FIELD_PATTERN,
                 pat.span,
                 "all the struct fields are matched to a wildcard pattern, consider using `..`",
-                None,
-                format!("try with `{type_name} {{ .. }}` instead"),
+                |diag| {
+                    diag.help(format!("try with `{type_name} {{ .. }}` instead"));
+                },
             );
             return;
         }
@@ -56,14 +58,15 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
                             }
                         }
 
-                        span_lint_and_help(
+                        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                        span_lint_and_then(
                             cx,
                             UNNEEDED_FIELD_PATTERN,
                             field.span,
-                            "you matched a field with a wildcard pattern, consider using `..` \
-                             instead",
-                            None,
-                            format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")),
+                            "you matched a field with a wildcard pattern, consider using `..` instead",
+                            |diag| {
+                                diag.help(format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")));
+                            },
                         );
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
index 935ed48dacc..a9ea11f4c2b 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_in_test;
 use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn};
 use rustc_hir::Expr;
@@ -79,13 +79,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage {
         };
 
         if let PanicExpn::Empty = panic_expn {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 MISSING_ASSERT_MESSAGE,
                 macro_call.span,
                 "assert without any message",
-                None,
-                "consider describing why the failing assert is problematic",
+                |diag| {
+                    diag.help("consider describing why the failing assert is problematic");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 68c158330ab..052d738b2e7 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -186,7 +186,7 @@ fn already_const(header: hir::FnHeader) -> bool {
 fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool {
     match abi {
         Abi::Rust => true,
-        // `const extern "C"` was stablized after 1.62.0
+        // `const extern "C"` was stabilized after 1.62.0
         Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN),
         // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled.
         _ => cx.tcx.features().const_extern_fn,
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 85029a5e6a0..7ee746365d1 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -1,10 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use clippy_utils::macros::span_is_local;
-use rustc_hir::def_id::DefIdMap;
+use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::AssocItem;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -68,33 +67,26 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
             }) = item.kind
             && let Some(trait_id) = trait_ref.trait_def_id()
         {
-            let mut provided: DefIdMap<&AssocItem> = cx
-                .tcx
-                .provided_trait_methods(trait_id)
-                .map(|assoc| (assoc.def_id, assoc))
+            let trait_item_ids: DefIdSet = items
+                .iter()
+                .filter_map(|impl_item| impl_item.trait_item_def_id)
                 .collect();
 
-            for impl_item in *items {
-                if let Some(def_id) = impl_item.trait_item_def_id {
-                    provided.remove(&def_id);
-                }
+            for assoc in cx
+                .tcx
+                .provided_trait_methods(trait_id)
+                .filter(|assoc| !trait_item_ids.contains(&assoc.def_id))
+            {
+                span_lint_and_then(
+                    cx,
+                    MISSING_TRAIT_METHODS,
+                    cx.tcx.def_span(item.owner_id),
+                    format!("missing trait method provided by default: `{}`", assoc.name),
+                    |diag| {
+                        diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method");
+                    },
+                );
             }
-
-            cx.tcx.with_stable_hashing_context(|hcx| {
-                for assoc in provided.values_sorted(&hcx, true) {
-                    let source_map = cx.tcx.sess.source_map();
-                    let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id));
-
-                    span_lint_and_help(
-                        cx,
-                        MISSING_TRAIT_METHODS,
-                        source_map.guess_head_span(item.span),
-                        format!("missing trait method provided by default: `{}`", assoc.name),
-                        Some(definition_span),
-                        "implement the method",
-                    );
-                }
-            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 9c5a8a0cfcd..6964d8c8dbb 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind};
@@ -324,13 +324,17 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
         if path_to_local_id(expr, self.var) {
             // Check that this is a read, not a write.
             if !is_in_assignment_position(self.cx, expr) {
-                span_lint_and_note(
+                span_lint_and_then(
                     self.cx,
                     MIXED_READ_WRITE_IN_EXPRESSION,
                     expr.span,
                     format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
-                    Some(self.write_expr.span),
-                    "whether read occurs before this write depends on evaluation order",
+                    |diag| {
+                        diag.span_note(
+                            self.write_expr.span,
+                            "whether read occurs before this write depends on evaluation order",
+                        );
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 305499f9da4..e9c5f64a255 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
@@ -121,17 +121,18 @@ impl EarlyLintPass for ModStyle {
         for folder in &folder_segments {
             if !mod_folders.contains(folder) {
                 if let Some((file, path)) = file_map.get(folder) {
-                    let mut correct = path.to_path_buf();
-                    correct.pop();
-                    correct.push(folder);
-                    correct.push("mod.rs");
-                    span_lint_and_help(
+                    span_lint_and_then(
                         cx,
                         SELF_NAMED_MODULE_FILES,
                         Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
                         format!("`mod.rs` files are required, found `{}`", path.display()),
-                        None,
-                        format!("move `{}` to `{}`", path.display(), correct.display(),),
+                        |diag| {
+                            let mut correct = path.to_path_buf();
+                            correct.pop();
+                            correct.push(folder);
+                            correct.push("mod.rs");
+                            diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),));
+                        },
                     );
                 }
             }
@@ -161,17 +162,18 @@ fn process_paths_for_mod_files<'a>(
 /// for code-sharing between tests.
 fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &SourceFile) {
     if path.ends_with("mod.rs") && !path.starts_with("tests") {
-        let mut mod_file = path.to_path_buf();
-        mod_file.pop();
-        mod_file.set_extension("rs");
-
-        span_lint_and_help(
+        span_lint_and_then(
             cx,
             MOD_MODULE_FILES,
             Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
             format!("`mod.rs` files are not allowed, found `{}`", path.display()),
-            None,
-            format!("move `{}` to `{}`", path.display(), mod_file.display()),
+            |diag| {
+                let mut mod_file = path.to_path_buf();
+                mod_file.pop();
+                mod_file.set_extension("rs");
+
+                diag.help(format!("move `{}` to `{}`", path.display(), mod_file.display()));
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index 67f9b52c352..32e7fde03b2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -1,7 +1,7 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::mir::PossibleBorrowerMap;
+use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode};
@@ -12,6 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, Mutability, Path, QPath};
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::{
     self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, ParamTy, ProjectionPredicate, Ty,
 };
@@ -107,6 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
             }
             && let count = needless_borrow_count(
                 cx,
+                &mut self.possible_borrowers,
                 fn_id,
                 cx.typeck_results().node_args(hir_id),
                 i,
@@ -155,9 +157,14 @@ fn path_has_args(p: &QPath<'_>) -> bool {
 /// The following constraints will be checked:
 /// * The borrowed expression meets all the generic type's constraints.
 /// * The generic type appears only once in the functions signature.
-/// * The borrowed value is Copy itself OR not a variable (created by a function call)
+/// * The borrowed value is:
+///   - `Copy` itself, or
+///   - the only use of a mutable reference, or
+///   - not a variable (created by a function call)
+#[expect(clippy::too_many_arguments)]
 fn needless_borrow_count<'tcx>(
     cx: &LateContext<'tcx>,
+    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
     fn_id: DefId,
     callee_args: ty::GenericArgsRef<'tcx>,
     arg_index: usize,
@@ -232,9 +239,9 @@ fn needless_borrow_count<'tcx>(
 
         let referent_ty = cx.typeck_results().expr_ty(referent);
 
-        if (!is_copy(cx, referent_ty) && !referent_ty.is_ref())
-            && let ExprKind::AddrOf(_, _, inner) = reference.kind
-            && !matches!(inner.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
+        if !(is_copy(cx, referent_ty)
+            || referent_ty.is_ref() && referent_used_exactly_once(cx, possible_borrowers, reference)
+            || matches!(referent.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)))
         {
             return false;
         }
@@ -337,6 +344,37 @@ fn is_mixed_projection_predicate<'tcx>(
     }
 }
 
+fn referent_used_exactly_once<'tcx>(
+    cx: &LateContext<'tcx>,
+    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
+    reference: &Expr<'tcx>,
+) -> bool {
+    if let Some(mir) = enclosing_mir(cx.tcx, reference.hir_id)
+        && let Some(local) = expr_local(cx.tcx, reference)
+        && let [location] = *local_assignments(mir, local).as_slice()
+        && let block_data = &mir.basic_blocks[location.block]
+        && let Some(statement) = block_data.statements.get(location.statement_index)
+        && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
+        && !place.is_indirect_first_projection()
+    {
+        let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
+        if possible_borrowers
+            .last()
+            .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id)
+        {
+            possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
+        }
+        let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
+        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
+        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
+        // itself. See the comment in that method for an explanation as to why.
+        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
+            && used_exactly_once(mir, place.local).unwrap_or(false)
+    } else {
+        false
+    }
+}
+
 // Iteratively replaces `param_ty` with `new_ty` in `args`, and similarly for each resulting
 // projected type that is a type parameter. Returns `false` if replacing the types would have an
 // effect on the function signature beyond substituting `new_ty` for `param_ty`.
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index f2e00cef7e9..a0bbf6b14b2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_self;
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::{snippet, snippet_opt};
@@ -278,9 +278,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                         }
                     }
 
-                    let spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];
-
-                    multispan_sugg(diag, "consider taking a reference instead", spans);
+                    diag.span_suggestion(
+                        input.span,
+                        "consider taking a reference instead",
+                        format!("&{}", snippet(cx, input.span, "_")),
+                        Applicability::MaybeIncorrect,
+                    );
                 };
 
                 span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 9d326c06eff..8232e69db39 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -273,7 +273,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
             }
             let snippet =
                 if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
-                    format!("assert!({}.len() > {});", &arr, &func)
+                    format!("assert!({arr}.len() > {func});")
                 } else {
                     return;
                 };
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 15bb328b446..6915cd40615 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -6,7 +6,7 @@ use std::ptr;
 
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_constant;
+use clippy_utils::is_in_const_context;
 use clippy_utils::macros::macro_backtrace;
 use clippy_utils::ty::{implements_trait, InteriorMut};
 use rustc_hir::def::{DefKind, Res};
@@ -406,7 +406,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Path(qpath) = &expr.kind {
             // Only lint if we use the const item inside a function.
-            if in_constant(cx, expr.hir_id) {
+            if is_in_const_context(cx) {
                 return;
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 8b8aabe7acc..aadd729f32a 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -243,7 +243,6 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                 owner_id,
                 ..
             }) => {
-                #[allow(trivial_casts)]
                 if let Node::Item(item) = cx.tcx.parent_hir_node(owner_id.into())
                     && let Some(trait_ref) = cx
                         .tcx
diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
index 9769da6d3e9..a0de5ea711c 100644
--- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
@@ -3,7 +3,7 @@ use rustc_lint::LateContext;
 use rustc_middle::ty;
 
 use clippy_utils::comparisons::{normalize_comparison, Rel};
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_isize_or_usize;
@@ -121,7 +121,7 @@ fn detect_absurd_comparison<'tcx>(
 fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
     let ty = cx.typeck_results().expr_ty(expr);
 
-    let cv = constant(cx, cx.typeck_results(), expr)?;
+    let cv = ConstEvalCtxt::new(cx).eval(expr)?;
 
     let which = match (ty.kind(), cv) {
         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum,
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index a7e381be743..bc71a4790b9 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -1,6 +1,6 @@
 use super::ARITHMETIC_SIDE_EFFECTS;
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
@@ -162,7 +162,7 @@ impl ArithmeticSideEffects {
         {
             return Some(n.get());
         }
-        if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) {
+        if let Some(Constant::Int(n)) = ConstEvalCtxt::new(cx).eval(expr) {
             return Some(n);
         }
         None
@@ -200,7 +200,7 @@ impl ArithmeticSideEffects {
         lhs: &'tcx hir::Expr<'_>,
         rhs: &'tcx hir::Expr<'_>,
     ) {
-        if constant_simple(cx, cx.typeck_results(), expr).is_some() {
+        if ConstEvalCtxt::new(cx).eval_simple(expr).is_some() {
             return;
         }
         if !matches!(
@@ -280,7 +280,7 @@ impl ArithmeticSideEffects {
         let Some(arg) = args.first() else {
             return;
         };
-        if constant_simple(cx, cx.typeck_results(), receiver).is_some() {
+        if ConstEvalCtxt::new(cx).eval_simple(receiver).is_some() {
             return;
         }
         let instance_ty = cx.typeck_results().expr_ty(receiver);
@@ -308,7 +308,7 @@ impl ArithmeticSideEffects {
         let hir::UnOp::Neg = un_op else {
             return;
         };
-        if constant(cx, cx.typeck_results(), un_expr).is_some() {
+        if ConstEvalCtxt::new(cx).eval(un_expr).is_some() {
             return;
         }
         let ty = cx.typeck_results().expr_ty(expr).peel_refs();
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index 545e680ce0d..4414056a467 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -166,7 +166,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
 }
 
 fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option<u128> {
-    match constant(cx, cx.typeck_results(), lit)? {
+    match ConstEvalCtxt::new(cx).eval(lit)? {
         Constant::Int(n) => Some(n),
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
index 7bf9b8ef866..c1317524396 100644
--- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
@@ -2,7 +2,7 @@
 
 use std::cmp::Ordering;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::layout::HasTyCtxt;
@@ -20,13 +20,14 @@ use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS};
 // Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
 fn comparison_to_const<'tcx>(
     cx: &LateContext<'tcx>,
-    typeck: &TypeckResults<'tcx>,
+    typeck: &'tcx TypeckResults<'tcx>,
     expr: &'tcx Expr<'tcx>,
 ) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
     if let ExprKind::Binary(operator, left, right) = expr.kind
         && let Ok(cmp_op) = CmpOp::try_from(operator.node)
     {
-        match (constant(cx, typeck, left), constant(cx, typeck, right)) {
+        let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck);
+        match (ecx.eval(left), ecx.eval(right)) {
             (Some(_), Some(_)) => None,
             (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
             (Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index ca3112ce5c4..e3029f8438e 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(
     if op == BinOpKind::Div
         && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
-        && let Some(Constant::Int(divisor)) = constant(cx, cx.typeck_results(), right)
+        && let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right)
     {
         let suggested_fn = match (method_path.ident.as_str(), divisor) {
             ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
diff --git a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
index 066e08f3bd4..24bfe2b050b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::same_type_and_consts;
 
@@ -34,12 +34,12 @@ fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>)
 
 fn check_op<'tcx>(
     cx: &LateContext<'tcx>,
-    tck: &TypeckResults<'tcx>,
+    tck: &'tcx TypeckResults<'tcx>,
     op: &Expr<'tcx>,
     other: &Expr<'tcx>,
     parent: &Expr<'tcx>,
 ) {
-    if constant_simple(cx, tck, op) == Some(Constant::Int(0)) {
+    if ConstEvalCtxt::with_env(cx.tcx, cx.param_env, tck).eval_simple(op) == Some(Constant::Int(0)) {
         if different_types(tck, other, parent) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index 0e5b440c50f..df6e6745596 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_with_source, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_item_name;
 use clippy_utils::sugg::Sugg;
@@ -17,12 +17,14 @@ pub(crate) fn check<'tcx>(
     right: &'tcx Expr<'_>,
 ) {
     if (op == BinOpKind::Eq || op == BinOpKind::Ne) && is_float(cx, left) {
-        let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) {
+        let typeck = cx.typeck_results();
+        let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck);
+        let left_is_local = match ecx.eval_with_source(left) {
             Some((c, s)) if !is_allowed(&c) => s.is_local(),
             Some(_) => return,
             None => true,
         };
-        let right_is_local = match constant_with_source(cx, cx.typeck_results(), right) {
+        let right_is_local = match ecx.eval_with_source(right) {
             Some((c, s)) if !is_allowed(&c) => s.is_local(),
             Some(_) => return,
             None => true,
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index 0879dcd9bcd..830be50c8ba 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{clip, peel_hir_expr_refs, unsext};
@@ -184,14 +184,13 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Exp
         && cx.typeck_results().expr_ty(right).peel_refs().is_integral()
         // `1 << 0` is a common pattern in bit manipulation code
         && !(cmp == BinOpKind::Shl
-            && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
-            && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)))
+            && ConstEvalCtxt::new(cx).eval_simple(right) == Some(Constant::Int(0))
+            && ConstEvalCtxt::new(cx).eval_simple(left) == Some(Constant::Int(1)))
 }
 
 fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span: Span, arg: Span) {
-    let lhs_const = constant_full_int(cx, cx.typeck_results(), left);
-    let rhs_const = constant_full_int(cx, cx.typeck_results(), right);
-    if match (lhs_const, rhs_const) {
+    let ecx = ConstEvalCtxt::new(cx);
+    if match (ecx.eval_full_int(left), ecx.eval_full_int(right)) {
         (Some(FullInt::S(lv)), Some(FullInt::S(rv))) => lv.abs() < rv.abs(),
         (Some(FullInt::U(lv)), Some(FullInt::U(rv))) => lv < rv,
         _ => return,
@@ -201,7 +200,7 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span
 }
 
 fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) -> bool {
-    if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) {
+    if let Some(Constant::Int(v)) = ConstEvalCtxt::new(cx).eval_simple(e).map(Constant::peel_refs) {
         let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() {
             ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
             ty::Uint(uty) => clip(cx.tcx, !0, uty),
diff --git a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
index 631d10f4a72..76eba7327cf 100644
--- a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 
@@ -15,13 +15,9 @@ pub(crate) fn check<'tcx>(
         && cx.typeck_results().expr_ty(left).is_integral()
         && cx.typeck_results().expr_ty(right).is_integral()
     {
-        span_lint_and_help(
-            cx,
-            INTEGER_DIVISION,
-            expr.span,
-            "integer division",
-            None,
-            "division of integers may cause loss of precision. consider using floats",
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| {
+            diag.help("division of integers may cause loss of precision. consider using floats");
+        });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
index d65fffac5a8..c83bdda347a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sext;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
@@ -42,15 +42,11 @@ fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     };
 
     if op.node == BinOpKind::Eq || op.node == BinOpKind::Ne {
-        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), rhs) {
-            return true;
-        }
-        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), lhs) {
-            return true;
-        }
+        let ecx = ConstEvalCtxt::new(cx);
+        matches!(ecx.eval(lhs), Some(Constant::Int(0))) || matches!(ecx.eval(rhs), Some(Constant::Int(0)))
+    } else {
+        false
     }
-
-    false
 }
 
 struct OperandInfo {
@@ -60,7 +56,7 @@ struct OperandInfo {
 }
 
 fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> {
-    match constant(cx, cx.typeck_results(), operand) {
+    match ConstEvalCtxt::new(cx).eval(operand) {
         Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() {
             ty::Int(ity) => {
                 let value = sext(cx.tcx, v, ity);
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index ea933168cfd..565294bb40a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -1,5 +1,5 @@
 use super::FLOAT_ARITHMETIC;
-use clippy_utils::consts::constant_simple;
+use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -55,7 +55,7 @@ impl Context {
             return;
         }
         let ty = cx.typeck_results().expr_ty(arg);
-        if constant_simple(cx, cx.typeck_results(), expr).is_none() && ty.is_floating_point() {
+        if ConstEvalCtxt::new(cx).eval_simple(expr).is_none() && ty.is_floating_point() {
             span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
             self.expr_id = Some(expr.hir_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index c2b27c9b229..82b9d10fbeb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_enclosing_block;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
@@ -64,10 +64,10 @@ pub(crate) fn check<'tcx>(
                         |diag| {
                             let lsnip = snippet(cx, l.span, "...").to_string();
                             let rsnip = snippet(cx, r.span, "...").to_string();
-                            multispan_sugg(
-                                diag,
+                            diag.multipart_suggestion(
                                 "use the values directly",
                                 vec![(left.span, lsnip), (right.span, rsnip)],
+                                Applicability::MachineApplicable,
                             );
                         },
                     );
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index d4906328ccb..ae02d22512e 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_res_lang_ctor, peel_blocks,
-    peel_hir_expr_while, CaptureKind,
+    can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, is_res_lang_ctor,
+    peel_blocks, peel_hir_expr_while, CaptureKind,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -294,7 +294,7 @@ fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         // Don't lint macros and constants
-        if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
+        if expr.span.from_expansion() || is_in_const_context(cx) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
index 2d20cbea698..267e2067e10 100644
--- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Item, ItemKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -57,24 +57,16 @@ impl EarlyLintPass for PartialPubFields {
 
         for field in fields {
             if all_priv && field.vis.kind.is_pub() {
-                span_lint_and_help(
-                    cx,
-                    PARTIAL_PUB_FIELDS,
-                    field.vis.span,
-                    msg,
-                    None,
-                    "consider using private field here",
-                );
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(cx, PARTIAL_PUB_FIELDS, field.vis.span, msg, |diag| {
+                    diag.help("consider using private field here");
+                });
                 return;
             } else if all_pub && !field.vis.kind.is_pub() {
-                span_lint_and_help(
-                    cx,
-                    PARTIAL_PUB_FIELDS,
-                    field.vis.span,
-                    msg,
-                    None,
-                    "consider using public field here",
-                );
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(cx, PARTIAL_PUB_FIELDS, field.vis.span, msg, |diag| {
+                    diag.help("consider using public field here");
+                });
                 return;
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index 0008f154ae3..18bfb588a11 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -21,8 +21,8 @@ declare_clippy_lint! {
     /// `PathBuf::from` instead.
     ///
     /// ### Known problems
-    /// `.join()` introduces an implicit `clone()`. `PathBuf::from` can alternativly be
-    /// used when the `PathBuf` is newly constructed. This will avoild the implicit clone.
+    /// `.join()` introduces an implicit `clone()`. `PathBuf::from` can alternatively be
+    /// used when the `PathBuf` is newly constructed. This will avoid the implicit clone.
     ///
     /// ### Example
     /// ```rust
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 9661a57b8b9..c1296b04387 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::{
     intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
 };
@@ -133,23 +133,25 @@ enum DerefPossible {
 fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool {
     let maybe_mismatch = find_first_mismatch(cx, pat);
     if let Some((span, mutability, level)) = maybe_mismatch {
-        span_lint_and_help(
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
             cx,
             PATTERN_TYPE_MISMATCH,
             span,
             "type of pattern does not match the expression type",
-            None,
-            format!(
-                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
-                match (deref_possible, level) {
-                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
-                    _ => "",
-                },
-                match mutability {
-                    Mutability::Mut => "&mut _",
-                    Mutability::Not => "&_",
-                },
-            ),
+            |diag| {
+                diag.help(format!(
+                    "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
+                    match (deref_possible, level) {
+                        (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
+                        _ => "",
+                    },
+                    match mutability {
+                        Mutability::Mut => "&mut _",
+                        Mutability::Not => "&_",
+                    },
+                ));
+            },
         );
         true
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/pub_use.rs b/src/tools/clippy/clippy_lints/src/pub_use.rs
index ab8f8a1689d..5b973a79eae 100644
--- a/src/tools/clippy/clippy_lints/src/pub_use.rs
+++ b/src/tools/clippy/clippy_lints/src/pub_use.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -42,14 +42,10 @@ impl EarlyLintPass for PubUse {
         if let ItemKind::Use(_) = item.kind
             && let VisibilityKind::Public = item.vis.kind
         {
-            span_lint_and_help(
-                cx,
-                PUB_USE,
-                item.span,
-                "using `pub use`",
-                None,
-                "move the exported item to a public module instead",
-            );
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(cx, PUB_USE, item.span, "using `pub use`", |diag| {
+                diag.help("move the exported item to a public module instead");
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index ef6b4d3aeab..e1e3ded2c79 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -7,7 +7,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
-    eq_expr_value, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
+    eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
     pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
     span_contains_comment,
 };
@@ -346,15 +346,13 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
             return;
         }
 
-        if !self.inside_try_block() && !in_constant(cx, stmt.hir_id) {
+        if !self.inside_try_block() && !is_in_const_context(cx) {
             check_let_some_else_return_none(cx, stmt);
         }
         self.check_manual_let_else(cx, stmt);
     }
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.inside_try_block()
-            && !in_constant(cx, expr.hir_id)
-            && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id)
+        if !self.inside_try_block() && !is_in_const_context(cx) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id)
         {
             check_is_none_or_err_and_early_return(cx, expr);
             check_if_let_some_or_err_and_early_return(cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
index f5e6cb804da..0a974bf9d2f 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 
 use clippy_utils::macros::span_is_local;
 use rustc_hir::{Expr, ExprKind, MatchSource};
@@ -39,13 +39,15 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
                 return;
             }
 
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 QUESTION_MARK_USED,
                 expr.span,
                 "question mark operator was used",
-                None,
-                "consider using a custom macro or match expression",
+                |diag| {
+                    diag.help("consider using a custom macro or match expression");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 829fb58bc65..81189fe517c 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,10 +1,10 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local};
+use clippy_utils::{get_parent_expr, higher, is_in_const_context, is_integer_const, path_to_local};
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
@@ -202,7 +202,7 @@ fn check_possible_range_contains(
     expr: &Expr<'_>,
     span: Span,
 ) {
-    if in_constant(cx, expr.hir_id) {
+    if is_in_const_context(cx) {
         return;
     }
 
@@ -319,7 +319,7 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
             _ => return None,
         };
         if let Some(id) = path_to_local(l) {
-            if let Some(c) = constant(cx, cx.typeck_results(), r) {
+            if let Some(c) = ConstEvalCtxt::new(cx).eval(r) {
                 return Some(RangeBounds {
                     val: c,
                     expr: r,
@@ -331,7 +331,7 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
                 });
             }
         } else if let Some(id) = path_to_local(r) {
-            if let Some(c) = constant(cx, cx.typeck_results(), l) {
+            if let Some(c) = ConstEvalCtxt::new(cx).eval(l) {
                 return Some(RangeBounds {
                     val: c,
                     expr: l,
@@ -451,8 +451,9 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
     }) = higher::Range::hir(expr)
         && let ty = cx.typeck_results().expr_ty(start)
         && let ty::Int(_) | ty::Uint(_) = ty.kind()
-        && let Some(start_idx) = constant(cx, cx.typeck_results(), start)
-        && let Some(end_idx) = constant(cx, cx.typeck_results(), end)
+        && let ecx = ConstEvalCtxt::new(cx)
+        && let Some(start_idx) = ecx.eval(start)
+        && let Some(end_idx) = ecx.eval(end)
         && let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx)
         && is_empty_range(limits, ordering)
     {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 3416a93e3c4..a1231c082e6 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
             let (fn_def_id, arg, arg_ty, clone_ret) =
                 unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));
 
-            let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
+            let from_borrow = cx.tcx.lang_items().get(LangItem::CloneFn) == Some(fn_def_id)
                 || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id)
                 || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id)
                     && is_type_lang_item(cx, arg_ty, LangItem::String));
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 82f22ad693d..1c10e84d3ca 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -1,7 +1,7 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::get_parent_expr;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{is_type_lang_item, peel_mid_ty_refs};
+use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::{get_parent_expr, peel_middle_ty_refs};
 use rustc_ast::util::parser::PREC_PREFIX;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@@ -82,13 +82,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
             && let ExprKind::Index(indexed, range, _) = addressee.kind
             && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull)
         {
-            let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr));
-            let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed));
+            let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr));
+            let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
             let parent_expr = get_parent_expr(cx, expr);
             let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX);
-            let mut app = Applicability::MachineApplicable;
 
-            let ((lint, msg), help, sugg) = if expr_ty == indexed_ty {
+            if expr_ty == indexed_ty {
                 if expr_ref_count > indexed_ref_count {
                     // Indexing takes self by reference and can't return a reference to that
                     // reference as it's a local variable. The only way this could happen is if
@@ -99,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                 }
                 let deref_count = indexed_ref_count - expr_ref_count;
 
-                let (lint, reborrow_str, help_str) = if mutability == Mutability::Mut {
+                let ((lint, msg), reborrow_str, help_msg) = if mutability == Mutability::Mut {
                     // The slice was used to reborrow the mutable reference.
                     (DEREF_BY_SLICING_LINT, "&mut *", "reborrow the original value instead")
                 } else if matches!(
@@ -113,8 +112,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                         a.kind,
                         Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. }))
                     )
-                }) {
-                    // The slice was used to make a temporary reference.
+                }) || (matches!(
+                    cx.typeck_results().expr_ty(indexed).ref_mutability(),
+                    Some(Mutability::Mut)
+                ) && mutability == Mutability::Not)
+                {
                     (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead")
                 } else if deref_count != 0 {
                     (DEREF_BY_SLICING_LINT, "", "dereference the original value instead")
@@ -122,38 +124,36 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                     (REDUNDANT_SLICING_LINT, "", "use the original value instead")
                 };
 
-                let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
-                let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
-                    format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
-                } else {
-                    format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
-                };
-
-                (lint, help_str, sugg)
+                span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+                    let mut app = Applicability::MachineApplicable;
+                    let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+                    let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
+                        format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
+                    } else {
+                        format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
+                    };
+                    diag.span_suggestion(expr.span, help_msg, sugg, app);
+                });
             } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                 if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
                     cx.param_env,
                     Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
                 ) {
                     if deref_ty == expr_ty {
-                        let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
-                        let sugg = if needs_parens_for_prefix {
-                            format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
-                        } else {
-                            format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
-                        };
-                        (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg)
-                    } else {
-                        return;
+                        let (lint, msg) = DEREF_BY_SLICING_LINT;
+                        span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+                            let mut app = Applicability::MachineApplicable;
+                            let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+                            let sugg = if needs_parens_for_prefix {
+                                format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+                            } else {
+                                format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+                            };
+                            diag.span_suggestion(expr.span, "dereference the original value instead", sugg, app);
+                        });
                     }
-                } else {
-                    return;
                 }
-            } else {
-                return;
-            };
-
-            span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg, app);
+            }
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs
index 467038523b4..002c6c41d52 100644
--- a/src/tools/clippy/clippy_lints/src/ref_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{BindingMode, Pat, PatKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -33,14 +33,10 @@ impl EarlyLintPass for RefPatterns {
         if let PatKind::Ident(BindingMode::REF, _, _) = pat.kind
             && !pat.span.from_expansion()
         {
-            span_lint_and_help(
-                cx,
-                REF_PATTERNS,
-                pat.span,
-                "usage of ref pattern",
-                None,
-                "consider using `&` for clarity instead",
-            );
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(cx, REF_PATTERNS, pat.span, "usage of ref pattern", |diag| {
+                diag.help("consider using `&` for clarity instead");
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 8cacb646f51..95014b23043 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -1,6 +1,6 @@
 use std::fmt::Display;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{def_path_def_ids, path_def_id, paths};
@@ -148,7 +148,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescape
 }
 
 fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
-    constant(cx, cx.typeck_results(), e).and_then(|c| match c {
+    ConstEvalCtxt::new(cx).eval(e).and_then(|c| match c {
         Constant::Str(s) => Some(s),
         _ => None,
     })
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
deleted file mode 100644
index 8e999f3e89a..00000000000
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-// This file is managed by `cargo dev rename_lint`. Prefer using that when possible.
-
-#[rustfmt::skip]
-pub static RENAMED_LINTS: &[(&str, &str)] = &[
-    ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
-    ("clippy::blacklisted_name", "clippy::disallowed_names"),
-    ("clippy::block_in_if_condition_expr", "clippy::blocks_in_conditions"),
-    ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_conditions"),
-    ("clippy::blocks_in_if_conditions", "clippy::blocks_in_conditions"),
-    ("clippy::box_vec", "clippy::box_collection"),
-    ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
-    ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
-    ("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"),
-    ("clippy::disallowed_method", "clippy::disallowed_methods"),
-    ("clippy::disallowed_type", "clippy::disallowed_types"),
-    ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
-    ("clippy::identity_conversion", "clippy::useless_conversion"),
-    ("clippy::if_let_some_result", "clippy::match_result_ok"),
-    ("clippy::incorrect_clone_impl_on_copy_type", "clippy::non_canonical_clone_impl"),
-    ("clippy::incorrect_partial_ord_impl_on_ord_type", "clippy::non_canonical_partial_ord_impl"),
-    ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"),
-    ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
-    ("clippy::new_without_default_derive", "clippy::new_without_default"),
-    ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
-    ("clippy::option_expect_used", "clippy::expect_used"),
-    ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
-    ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
-    ("clippy::option_unwrap_used", "clippy::unwrap_used"),
-    ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"),
-    ("clippy::ref_in_deref", "clippy::needless_borrow"),
-    ("clippy::result_expect_used", "clippy::expect_used"),
-    ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
-    ("clippy::result_unwrap_used", "clippy::unwrap_used"),
-    ("clippy::single_char_push_str", "clippy::single_char_add_str"),
-    ("clippy::stutter", "clippy::module_name_repetitions"),
-    ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"),
-    ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
-    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
-    ("clippy::zero_width_space", "clippy::invisible_characters"),
-    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
-    ("clippy::clone_double_ref", "suspicious_double_ref_op"),
-    ("clippy::cmp_nan", "invalid_nan_comparisons"),
-    ("clippy::drop_bounds", "drop_bounds"),
-    ("clippy::drop_copy", "dropping_copy_types"),
-    ("clippy::drop_ref", "dropping_references"),
-    ("clippy::fn_null_check", "useless_ptr_null_checks"),
-    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
-    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
-    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
-    ("clippy::forget_copy", "forgetting_copy_types"),
-    ("clippy::forget_ref", "forgetting_references"),
-    ("clippy::into_iter_on_array", "array_into_iter"),
-    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
-    ("clippy::invalid_ref", "invalid_value"),
-    ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"),
-    ("clippy::let_underscore_drop", "let_underscore_drop"),
-    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
-    ("clippy::panic_params", "non_fmt_panics"),
-    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
-    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
-    ("clippy::undropped_manually_drops", "undropped_manually_drops"),
-    ("clippy::unknown_clippy_lints", "unknown_lints"),
-    ("clippy::unused_label", "unused_labels"),
-    ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
-];
diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
index 792d8fc88f0..678681ea425 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::VecArgs;
 use clippy_utils::macros::matching_root_macro_call;
@@ -69,7 +69,7 @@ fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) {
         && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
         && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
         && !len_expr.span.from_expansion()
-        && let Some(Constant::Int(2..)) = constant(cx, cx.typeck_results(), expr_or_init(cx, len_expr))
+        && let Some(Constant::Int(2..)) = ConstEvalCtxt::new(cx).eval(expr_or_init(cx, len_expr))
     {
         emit_lint(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 8ced47b48a4..13016cdadb0 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -395,7 +395,7 @@ fn check_final_expr<'tcx>(
             // Returns may be used to turn an expression into a statement in rustc's AST.
             // This allows the addition of attributes, like `#[allow]` (See: clippy#9361)
             // `#[expect(clippy::needless_return)]` needs to be handled separatly to
-            // actually fullfil the expectation (clippy::#12998)
+            // actually fulfill the expectation (clippy::#12998)
             match cx.tcx.hir().attrs(expr.hir_id) {
                 [] => {},
                 [attr] => {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 7615c21276d..09f1c112352 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -92,11 +92,10 @@ impl SemicolonBlock {
             semi_span,
             "consider moving the `;` inside the block for consistent formatting",
             |diag| {
-                multispan_sugg_with_applicability(
-                    diag,
+                diag.multipart_suggestion(
                     "put the `;` here",
+                    vec![(remove_span, String::new()), (insert_span, ";".to_owned())],
                     Applicability::MachineApplicable,
-                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
                 );
             },
         );
@@ -124,11 +123,10 @@ impl SemicolonBlock {
             block.span,
             "consider moving the `;` outside the block for consistent formatting",
             |diag| {
-                multispan_sugg_with_applicability(
-                    diag,
+                diag.multipart_suggestion(
                     "put the `;` here",
+                    vec![(remove_span, String::new()), (insert_span, ";".to_owned())],
                     Applicability::MachineApplicable,
-                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
                 );
             },
         );
diff --git a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
index 5e65b9fa517..e6fe7649397 100644
--- a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
+++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
@@ -12,8 +12,8 @@ use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `contains` to see if a value is not
-    /// present on `HashSet` followed by a `insert`.
+    /// Checks for usage of `contains` to see if a value is not present
+    /// in a set like `HashSet` or `BTreeSet`, followed by an `insert`.
     ///
     /// ### Why is this bad?
     /// Using just `insert` and checking the returned `bool` is more efficient.
@@ -45,12 +45,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.80.0"]
     pub SET_CONTAINS_OR_INSERT,
     nursery,
-    "call to `HashSet::contains` followed by `HashSet::insert`"
+    "call to `<set>::contains` followed by `<set>::insert`"
 }
 
-declare_lint_pass!(HashsetInsertAfterContains => [SET_CONTAINS_OR_INSERT]);
+declare_lint_pass!(SetContainsOrInsert => [SET_CONTAINS_OR_INSERT]);
 
-impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains {
+impl<'tcx> LateLintPass<'tcx> for SetContainsOrInsert {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !expr.span.from_expansion()
             && let Some(higher::If {
@@ -58,14 +58,14 @@ impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains {
                 then: then_expr,
                 ..
             }) = higher::If::hir(expr)
-            && let Some(contains_expr) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr)
+            && let Some((contains_expr, sym)) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr)
             && let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr)
         {
             span_lint(
                 cx,
                 SET_CONTAINS_OR_INSERT,
                 vec![contains_expr.span, insert_expr.span],
-                "usage of `HashSet::insert` after `HashSet::contains`",
+                format!("usage of `{sym}::insert` after `{sym}::contains`"),
             );
         }
     }
@@ -77,7 +77,11 @@ struct OpExpr<'tcx> {
     span: Span,
 }
 
-fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol: Symbol) -> Option<OpExpr<'tcx>> {
+fn try_parse_op_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    symbol: Symbol,
+) -> Option<(OpExpr<'tcx>, Symbol)> {
     let expr = peel_hir_expr_while(expr, |e| {
         if let ExprKind::Unary(UnOp::Not, e) = e.kind {
             Some(e)
@@ -97,11 +101,12 @@ fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol:
         });
         let receiver = receiver.peel_borrows();
         let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
-        if value.span.eq_ctxt(expr.span)
-            && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet)
-            && path.ident.name == symbol
-        {
-            return Some(OpExpr { receiver, value, span });
+        if value.span.eq_ctxt(expr.span) && path.ident.name == symbol {
+            for sym in &[sym::HashSet, sym::BTreeSet] {
+                if is_type_diagnostic_item(cx, receiver_ty, *sym) {
+                    return Some((OpExpr { receiver, value, span }, *sym));
+                }
+            }
         }
     }
     None
@@ -113,7 +118,7 @@ fn find_insert_calls<'tcx>(
     expr: &'tcx Expr<'_>,
 ) -> Option<OpExpr<'tcx>> {
     for_each_expr(cx, expr, |e| {
-        if let Some(insert_expr) = try_parse_op_call(cx, e, sym!(insert))
+        if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym!(insert))
             && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver)
             && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value)
         {
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 80f5fd0b494..7ae0310b6d9 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::is_local_used;
 use rustc_data_structures::fx::FxHashMap;
@@ -194,14 +194,9 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span)
             (SHADOW_UNRELATED, msg)
         },
     };
-    span_lint_and_note(
-        cx,
-        lint,
-        span,
-        msg,
-        Some(cx.tcx.hir().span(shadowed)),
-        "previous binding is here",
-    );
+    span_lint_and_then(cx, lint, span, msg, |diag| {
+        diag.span_note(cx.tcx.hir().span(shadowed), "previous binding is here");
+    });
 }
 
 /// Returns true if the expression is a simple transformation of a local binding such as `&x`
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
index 72feb977c31..d92b890950a 100644
--- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
+++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{GenericParam, GenericParamKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -48,13 +48,15 @@ impl EarlyLintPass for SingleCharLifetimeNames {
 
         if let GenericParamKind::Lifetime = param.kind {
             if !param.is_placeholder && param.ident.as_str().len() <= 2 {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     ctx,
                     SINGLE_CHAR_LIFETIME_NAMES,
                     param.ident.span,
                     "single-character lifetime names are likely uninformative",
-                    None,
-                    "use a more informative name",
+                    |diag| {
+                        diag.help("use a more informative name");
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
index 8d7f12af86e..b3d32a6d7d8 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::path_def_id;
-use clippy_utils::ty::peel_mid_ty_refs;
+use clippy_utils::{path_def_id, peel_middle_ty_refs};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -60,7 +59,7 @@ impl LateLintPass<'_> for SizeOfRef {
             && let Some(def_id) = path_def_id(cx, path)
             && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
             && let arg_ty = cx.typeck_results().expr_ty(arg)
-            && peel_mid_ty_refs(arg_ty).1 > 1
+            && peel_middle_ty_refs(arg_ty).1 > 1
         {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index 12b70075a3d..974e21df817 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -1,11 +1,15 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_config::msrvs::Msrv;
+use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
+use rustc_attr::{StabilityLevel, StableSince};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{HirId, Path, PathSegment};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
+use rustc_semver::RustcVersion;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
 use rustc_span::{sym, Span};
@@ -66,6 +70,10 @@ declare_clippy_lint! {
     /// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
     /// is also useful for crates migrating to become `no_std` compatible.
     ///
+    /// ### Known problems
+    /// The lint is only partially aware of the required MSRV for items that were originally in `std` but moved
+    /// to `core`.
+    ///
     /// ### Example
     /// ```no_run
     /// # extern crate alloc;
@@ -81,20 +89,30 @@ declare_clippy_lint! {
     "type is imported from alloc when available in core"
 }
 
-#[derive(Default)]
 pub struct StdReexports {
     // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen
     // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
     // when the path could be also be used to access the module.
     prev_span: Span,
+    msrv: Msrv,
 }
+
+impl StdReexports {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            prev_span: Span::default(),
+            msrv: conf.msrv.clone(),
+        }
+    }
+}
+
 impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]);
 
 impl<'tcx> LateLintPass<'tcx> for StdReexports {
     fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) {
         if let Res::Def(_, def_id) = path.res
             && let Some(first_segment) = get_first_segment(path)
-            && is_stable(cx, def_id)
+            && is_stable(cx, def_id, &self.msrv)
             && !in_external_macro(cx.sess(), path.span)
             && !is_from_proc_macro(cx, &first_segment.ident)
         {
@@ -118,19 +136,27 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                 _ => return,
             };
             if first_segment.ident.span != self.prev_span {
-                span_lint_and_sugg(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     lint,
                     first_segment.ident.span,
                     format!("used import from `{used_mod}` instead of `{replace_with}`"),
-                    format!("consider importing the item from `{replace_with}`"),
-                    replace_with.to_string(),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(
+                            first_segment.ident.span,
+                            format!("consider importing the item from `{replace_with}`"),
+                            replace_with.to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
                 self.prev_span = first_segment.ident.span;
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 /// Returns the first named segment of a [`Path`].
@@ -146,16 +172,29 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>>
     }
 }
 
-/// Checks if all ancestors of `def_id` are stable, to avoid linting
-/// [unstable moves](https://github.com/rust-lang/rust/pull/95956)
-fn is_stable(cx: &LateContext<'_>, mut def_id: DefId) -> bool {
+/// Checks if all ancestors of `def_id` meet `msrv` to avoid linting [unstable moves](https://github.com/rust-lang/rust/pull/95956)
+/// or now stable moves that were once unstable.
+///
+/// Does not catch individually moved items
+fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: &Msrv) -> bool {
     loop {
-        if cx
-            .tcx
-            .lookup_stability(def_id)
-            .map_or(false, |stability| stability.is_unstable())
+        if let Some(stability) = cx.tcx.lookup_stability(def_id)
+            && let StabilityLevel::Stable {
+                since,
+                allowed_through_unstable_modules: false,
+            } = stability.level
         {
-            return false;
+            let stable = match since {
+                StableSince::Version(v) => {
+                    msrv.meets(RustcVersion::new(v.major.into(), v.minor.into(), v.patch.into()))
+                },
+                StableSince::Current => msrv.current().is_none(),
+                StableSince::Err => false,
+            };
+
+            if !stable {
+                return false;
+            }
         }
 
         match cx.tcx.opt_parent(def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 7da661485ab..cfc387886dc 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{
@@ -399,17 +399,16 @@ impl<'tcx> LateLintPass<'tcx> for StrToString {
             && let ty::Ref(_, ty, ..) = ty.kind()
             && ty.is_str()
         {
-            let mut applicability = Applicability::MachineApplicable;
-            let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability);
-
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 STR_TO_STRING,
                 expr.span,
                 "`to_string()` called on a `&str`",
-                "try",
-                format!("{snippet}.to_owned()"),
-                applicability,
+                |diag| {
+                    let mut applicability = Applicability::MachineApplicable;
+                    let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability);
+                    diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability);
+                },
             );
         }
     }
@@ -455,13 +454,15 @@ impl<'tcx> LateLintPass<'tcx> for StringToString {
             && let ty = cx.typeck_results().expr_ty(self_arg)
             && is_type_lang_item(cx, ty, LangItem::String)
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 STRING_TO_STRING,
                 expr.span,
                 "`to_string()` called on a `String`",
-                None,
-                "consider using `.clone()`",
+                |diag| {
+                    diag.help("consider using `.clone()`");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
index d150a5f858a..d1d822a5532 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::numeric_literal::NumericLiteral;
 use clippy_utils::source::snippet;
 use rustc_ast::LitKind;
@@ -43,14 +43,19 @@ impl LateLintPass<'_> for ConfusingXorAndPow {
             && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node)
                 .is_some_and(|x| x.is_decimal())
         {
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 SUSPICIOUS_XOR_USED_AS_POW,
                 expr.span,
                 "`^` is not the exponentiation operator",
-                "did you mean to write",
-                format!("{}.pow({})", lit_left.node, lit_right.node),
-                Applicability::MaybeIncorrect,
+                |diag| {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        "did you mean to write",
+                        format!("{}.pow({})", lit_left.node, lit_right.node),
+                        Applicability::MaybeIncorrect,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 93bad865809..197011cde3a 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_indent, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
 
-use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core};
+use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core};
 use itertools::Itertools;
 
 use rustc_hir::intravisit::{walk_expr, Visitor};
@@ -170,7 +170,7 @@ fn generate_swap_warning<'tcx>(
 
 /// Implementation of the `MANUAL_SWAP` lint.
 fn check_manual_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
-    if in_constant(cx, block.hir_id) {
+    if is_in_const_context(cx) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
index 58e42892c41..25d0a16e2ab 100644
--- a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl};
@@ -61,13 +61,15 @@ impl LateLintPass<'_> for TestsOutsideTestModule {
             && is_in_test_function(cx.tcx, body.id().hir_id)
             && !is_in_cfg_test(cx.tcx, body.id().hir_id)
         {
-            span_lint_and_note(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 TESTS_OUTSIDE_TEST_MODULE,
                 sp,
                 "this function marked with #[test] is outside a #[cfg(test)] module",
-                None,
-                "move it to a testing module marked with #[cfg(test)]",
+                |diag| {
+                    diag.note("move it to a testing module marked with #[cfg(test)]");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 9c6813a54b9..373bf61d8ff 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -21,7 +21,7 @@ mod wrong_transmute;
 
 use clippy_config::msrvs::Msrv;
 use clippy_config::Conf;
-use clippy_utils::in_constant;
+use clippy_utils::is_in_const_context;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -595,7 +595,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
             // - from/to bits (https://github.com/rust-lang/rust/issues/73736)
             // - dereferencing raw pointers (https://github.com/rust-lang/rust/issues/51911)
             // - char conversions (https://github.com/rust-lang/rust/issues/89259)
-            let const_context = in_constant(cx, e.hir_id);
+            let const_context = is_in_const_context(cx);
 
             let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
                 [] => (cx.typeck_results().expr_ty(arg), false),
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
index b26365e34ab..7acf3be51fb 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
 use rustc_hir::{Expr, ExprKind};
@@ -33,10 +33,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
         // Catching:
         // transmute over constants that resolve to `null`.
         ExprKind::Path(ref _qpath)
-            if matches!(
-                constant(cx, cx.typeck_results(), casts_peeled),
-                Some(Constant::RawPtr(0))
-            ) =>
+            if matches!(ConstEvalCtxt::new(cx).eval(casts_peeled), Some(Constant::RawPtr(0))) =>
         {
             lint_expr(cx, expr);
             true
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
index 471bd44b5d5..544014bd32b 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
 use rustc_hir::{Expr, ExprKind};
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
 
     // Catching transmute over constants that resolve to `null`.
     if let ExprKind::Path(ref _qpath) = arg.kind
-        && let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg)
+        && let Some(Constant::RawPtr(0)) = ConstEvalCtxt::new(cx).eval(arg)
     {
         span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
         return true;
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 83cc9f2d8df..2fcfc71a8c7 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -48,15 +48,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
                 let inner_snippet = snippet(cx, inner.span, "..");
                 let suggestion = match &inner.kind {
                     TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => {
-                        format!("&{ltopt}({})", &inner_snippet)
+                        format!("&{ltopt}({inner_snippet})")
                     },
                     TyKind::Path(qpath)
                         if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
                             .map_or(false, |bounds| bounds.len() > 1) =>
                     {
-                        format!("&{ltopt}({})", &inner_snippet)
+                        format!("&{ltopt}({inner_snippet})")
                     },
-                    _ => format!("&{ltopt}{}", &inner_snippet),
+                    _ => format!("&{ltopt}{inner_snippet}"),
                 };
                 span_lint_and_sugg(
                     cx,
@@ -82,16 +82,14 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
 // Returns true if given type is `Any` trait.
 fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool {
     if let TyKind::TraitObject(traits, ..) = t.kind {
-        return traits
-            .iter()
-            .any(|(bound, _)| {
-                if let Some(trait_did) = bound.trait_ref.trait_def_id()
-                    && cx.tcx.is_diagnostic_item(sym::Any, trait_did)
-                {
-                    return true;
-                }
-                false
-            });
+        return traits.iter().any(|(bound, _)| {
+            if let Some(trait_did) = bound.trait_ref.trait_def_id()
+                && cx.tcx.is_diagnostic_item(sym::Any, trait_did)
+            {
+                return true;
+            }
+            false
+        });
     }
 
     false
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
index f6c2d8d5a5e..d691f1878b1 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_errors::Applicability;
@@ -13,14 +13,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
     let app = Applicability::Unspecified;
     if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
         if let Some(alternate) = match_buffer_type(cx, qpath) {
-            span_lint_and_sugg(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 RC_BUFFER,
                 hir_ty.span,
                 "usage of `Rc<T>` when T is a buffer type",
-                "try",
-                format!("Rc<{alternate}>"),
-                app,
+                |diag| {
+                    diag.span_suggestion(hir_ty.span, "try", format!("Rc<{alternate}>"), app);
+                },
             );
         } else {
             let Some(ty) = qpath_generic_tys(qpath).next() else {
@@ -35,31 +36,37 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 Some(ty) => ty.span,
                 None => return false,
             };
-            let mut applicability = app;
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 RC_BUFFER,
                 hir_ty.span,
                 "usage of `Rc<T>` when T is a buffer type",
-                "try",
-                format!(
-                    "Rc<[{}]>",
-                    snippet_with_applicability(cx, inner_span, "..", &mut applicability)
-                ),
-                app,
+                |diag| {
+                    let mut applicability = app;
+                    diag.span_suggestion(
+                        hir_ty.span,
+                        "try",
+                        format!(
+                            "Rc<[{}]>",
+                            snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+                        ),
+                        app,
+                    );
+                },
             );
             return true;
         }
     } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
         if let Some(alternate) = match_buffer_type(cx, qpath) {
-            span_lint_and_sugg(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 RC_BUFFER,
                 hir_ty.span,
                 "usage of `Arc<T>` when T is a buffer type",
-                "try",
-                format!("Arc<{alternate}>"),
-                app,
+                |diag| {
+                    diag.span_suggestion(hir_ty.span, "try", format!("Arc<{alternate}>"), app);
+                },
             );
         } else if let Some(ty) = qpath_generic_tys(qpath).next() {
             let Some(id) = path_def_id(cx, ty) else { return false };
@@ -71,18 +78,23 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 Some(ty) => ty.span,
                 None => return false,
             };
-            let mut applicability = app;
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 RC_BUFFER,
                 hir_ty.span,
                 "usage of `Arc<T>` when T is a buffer type",
-                "try",
-                format!(
-                    "Arc<[{}]>",
-                    snippet_with_applicability(cx, inner_span, "..", &mut applicability)
-                ),
-                app,
+                |diag| {
+                    let mut applicability = app;
+                    diag.span_suggestion(
+                        hir_ty.span,
+                        "try",
+                        format!(
+                            "Arc<[{}]>",
+                            snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+                        ),
+                        app,
+                    );
+                },
             );
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
index afc31921704..7b13debc01e 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, QPath};
@@ -13,14 +13,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
         && let Some(id) = path_def_id(cx, arg)
         && cx.tcx.is_diagnostic_item(sym::Mutex, id)
     {
-        span_lint_and_help(
-            cx,
-            RC_MUTEX,
-            hir_ty.span,
-            "usage of `Rc<Mutex<_>>`",
-            None,
-            "consider using `Rc<RefCell<_>>` or `Arc<Mutex<_>>` instead",
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, RC_MUTEX, hir_ty.span, "usage of `Rc<Mutex<_>>`", |diag| {
+            diag.help("consider using `Rc<RefCell<_>>` or `Arc<Mutex<_>>` instead");
+        });
         return true;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 3ab30bf5dba..f51c5f74d99 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -1,7 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::visitors::{for_each_expr, Descend};
@@ -129,13 +129,15 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 block.span
             };
 
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 UNDOCUMENTED_UNSAFE_BLOCKS,
                 span,
                 "unsafe block missing a safety comment",
-                None,
-                "consider adding a safety comment on the preceding line",
+                |diag| {
+                    diag.help("consider adding a safety comment on the preceding line");
+                },
             );
         }
 
@@ -145,13 +147,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
             && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, tail.span, tail.hir_id)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, tail, pos)
         {
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 UNNECESSARY_SAFETY_COMMENT,
                 tail.span,
                 "expression has unnecessary safety comment",
-                Some(help_span),
-                "consider removing the safety comment",
+                |diag| {
+                    diag.span_help(help_span, "consider removing the safety comment");
+                },
             );
         }
     }
@@ -168,13 +171,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
             && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, stmt.span, stmt.hir_id)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, expr, pos)
         {
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 UNNECESSARY_SAFETY_COMMENT,
                 stmt.span,
                 "statement has unnecessary safety comment",
-                Some(help_span),
-                "consider removing the safety comment",
+                |diag| {
+                    diag.span_help(help_span, "consider removing the safety comment");
+                },
             );
         }
     }
@@ -210,13 +214,15 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                         item.span
                     };
 
-                    span_lint_and_help(
+                    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                    span_lint_and_then(
                         cx,
                         UNDOCUMENTED_UNSAFE_BLOCKS,
                         span,
                         "unsafe impl missing a safety comment",
-                        None,
-                        "consider adding a safety comment on the preceding line",
+                        |diag| {
+                            diag.help("consider adding a safety comment on the preceding line");
+                        },
                     );
                 }
             },
@@ -225,13 +231,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
-                    span_lint_and_help(
+                    span_lint_and_then(
                         cx,
                         UNNECESSARY_SAFETY_COMMENT,
                         span,
                         "impl has unnecessary safety comment",
-                        Some(help_span),
-                        "consider removing the safety comment",
+                        |diag| {
+                            diag.span_help(help_span, "consider removing the safety comment");
+                        },
                     );
                 }
             },
@@ -246,13 +253,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                     ) {
                         let (span, help_span) = mk_spans(pos);
 
-                        span_lint_and_help(
+                        span_lint_and_then(
                             cx,
                             UNNECESSARY_SAFETY_COMMENT,
                             span,
                             format!("{} has unnecessary safety comment", item.kind.descr()),
-                            Some(help_span),
-                            "consider removing the safety comment",
+                            |diag| {
+                                diag.span_help(help_span, "consider removing the safety comment");
+                            },
                         );
                     }
                 }
@@ -263,13 +271,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
-                    span_lint_and_help(
+                    span_lint_and_then(
                         cx,
                         UNNECESSARY_SAFETY_COMMENT,
                         span,
                         format!("{} has unnecessary safety comment", item.kind.descr()),
-                        Some(help_span),
-                        "consider removing the safety comment",
+                        |diag| {
+                            diag.span_help(help_span, "consider removing the safety comment");
+                        },
                     );
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index d42697b31d1..e1fc644e4ce 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use clippy_utils::macros::span_is_local;
 use clippy_utils::source::snippet;
@@ -105,45 +105,51 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
 
     let string = snippet(cx, span, "");
     if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
-        span_lint_and_sugg(
-            cx,
-            INVISIBLE_CHARACTERS,
-            span,
-            "invisible character detected",
-            "consider replacing the string with",
-            string
-                .replace('\u{200B}', "\\u{200B}")
-                .replace('\u{ad}', "\\u{AD}")
-                .replace('\u{2060}', "\\u{2060}"),
-            Applicability::MachineApplicable,
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, INVISIBLE_CHARACTERS, span, "invisible character detected", |diag| {
+            diag.span_suggestion(
+                span,
+                "consider replacing the string with",
+                string
+                    .replace('\u{200B}', "\\u{200B}")
+                    .replace('\u{ad}', "\\u{AD}")
+                    .replace('\u{2060}', "\\u{2060}"),
+                Applicability::MachineApplicable,
+            );
+        });
     }
 
     if string.chars().any(|c| c as u32 > 0x7F) {
-        span_lint_and_sugg(
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
             cx,
             NON_ASCII_LITERAL,
             span,
             "literal non-ASCII character detected",
-            "consider replacing the string with",
-            if is_lint_allowed(cx, UNICODE_NOT_NFC, id) {
-                escape(string.chars())
-            } else {
-                escape(string.nfc())
+            |diag| {
+                diag.span_suggestion(
+                    span,
+                    "consider replacing the string with",
+                    if is_lint_allowed(cx, UNICODE_NOT_NFC, id) {
+                        escape(string.chars())
+                    } else {
+                        escape(string.nfc())
+                    },
+                    Applicability::MachineApplicable,
+                );
             },
-            Applicability::MachineApplicable,
         );
     }
 
     if is_lint_allowed(cx, NON_ASCII_LITERAL, id) && string.chars().zip(string.nfc()).any(|(a, b)| a != b) {
-        span_lint_and_sugg(
-            cx,
-            UNICODE_NOT_NFC,
-            span,
-            "non-NFC Unicode sequence detected",
-            "consider replacing the string with",
-            string.nfc().collect::<String>(),
-            Applicability::MachineApplicable,
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, UNICODE_NOT_NFC, span, "non-NFC Unicode sequence detected", |diag| {
+            diag.span_suggestion(
+                span,
+                "consider replacing the string with",
+                string.nfc().collect::<String>(),
+                Applicability::MachineApplicable,
+            );
+        });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
new file mode 100644
index 00000000000..297288db0a5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
@@ -0,0 +1,59 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::{ExprKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `Result::ok()` without using the returned `Option`.
+    ///
+    /// ### Why is this bad?
+    /// Using `Result::ok()` may look like the result is checked like `unwrap` or `expect` would do
+    /// but it only silences the warning caused by `#[must_use]` on the `Result`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # fn some_function() -> Result<(), ()> { Ok(()) }
+    /// some_function().ok();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # fn some_function() -> Result<(), ()> { Ok(()) }
+    /// let _ = some_function();
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub UNUSED_RESULT_OK,
+    restriction,
+    "Use of `.ok()` to silence `Result`'s `#[must_use]` is misleading. Use `let _ =` instead."
+}
+declare_lint_pass!(UnusedResultOk => [UNUSED_RESULT_OK]);
+
+impl LateLintPass<'_> for UnusedResultOk {
+    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
+        if let StmtKind::Semi(expr) = stmt.kind
+            && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
+            && ok_path.ident.as_str() == "ok"
+            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+            && !in_external_macro(cx.sess(), stmt.span)
+        {
+            let ctxt = expr.span.ctxt();
+            let mut applicability = Applicability::MaybeIncorrect;
+            let snippet = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0;
+            let sugg = format!("let _ = {snippet}");
+            span_lint_and_sugg(
+                cx,
+                UNUSED_RESULT_OK,
+                expr.span,
+                "ignoring a result with `.ok()` is misleading",
+                "consider using `let _ =` and removing the call to `.ok()` instead",
+                sugg,
+                applicability,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index b017a6bf665..7c2e23995c1 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
@@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
         if let ExprKind::Call(func, [arg]) = &expr.kind
             && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
             && match_def_path(cx, *def_id, &paths::SYMBOL_INTERN)
-            && let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg)
+            && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg)
             && let value = Symbol::intern(&arg).as_u32()
             && let Some(&def_id) = self.symbol_map.get(&value)
         {
@@ -199,7 +199,7 @@ impl InterningDefinedSymbol {
             });
         }
         // is a string constant
-        if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
+        if let Some(Constant::Str(s)) = ConstEvalCtxt::new(cx).eval_simple(expr) {
             let value = Symbol::intern(&s).as_u32();
             // ...which matches a symbol constant
             if let Some(&def_id) = self.symbol_map.get(&value) {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 980437259c3..0ffcb433481 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::def_path_res;
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir as hir;
@@ -32,9 +32,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
         let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
         if mod_name.as_str() == "paths"
             && let hir::ItemKind::Const(.., body_id) = item.kind
-            && let body = cx.tcx.hir().body(body_id)
-            && let typeck_results = cx.tcx.typeck_body(body_id)
-            && let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value)
+            && let Some(Constant::Vec(path)) =
+                ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(item.owner_id), cx.tcx.typeck(item.owner_id))
+                    .eval_simple(cx.tcx.hir().body(body_id).value)
             && let Some(path) = path
                 .iter()
                 .map(|x| {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index 84f84781e71..df342e48d63 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -1,4 +1,3 @@
-use crate::utils::internal_lints::metadata_collector::is_deprecated_lint;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::{is_lint_allowed, match_def_path, paths};
@@ -87,82 +86,32 @@ declare_clippy_lint! {
     "found clippy lint without `clippy::version` attribute"
 }
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for cases of an auto-generated deprecated lint without an updated reason,
-    /// i.e. `"default deprecation note"`.
-    ///
-    /// ### Why is this bad?
-    /// Indicates that the documentation is incomplete.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// declare_deprecated_lint! {
-    ///     /// ### What it does
-    ///     /// Nothing. This lint has been deprecated.
-    ///     ///
-    ///     /// ### Deprecation reason
-    ///     /// TODO
-    ///     #[clippy::version = "1.63.0"]
-    ///     pub COOL_LINT,
-    ///     "default deprecation note"
-    /// }
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// declare_deprecated_lint! {
-    ///     /// ### What it does
-    ///     /// Nothing. This lint has been deprecated.
-    ///     ///
-    ///     /// ### Deprecation reason
-    ///     /// This lint has been replaced by `cooler_lint`
-    ///     #[clippy::version = "1.63.0"]
-    ///     pub COOL_LINT,
-    ///     "this lint has been replaced by `cooler_lint`"
-    /// }
-    /// ```
-    pub DEFAULT_DEPRECATION_REASON,
-    internal,
-    "found 'default deprecation note' in a deprecated lint declaration"
-}
-
 #[derive(Clone, Debug, Default)]
 pub struct LintWithoutLintPass {
     declared_lints: FxHashMap<Symbol, Span>,
     registered_lints: FxHashSet<Symbol>,
 }
 
-impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE, DEFAULT_DEPRECATION_REASON]);
+impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE]);
 
 impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id())
-            || is_lint_allowed(cx, DEFAULT_DEPRECATION_REASON, item.hir_id())
-        {
+        if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) {
             return;
         }
 
         if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
-            let is_lint_ref_ty = is_lint_ref_type(cx, ty);
-            if is_deprecated_lint(cx, ty) || is_lint_ref_ty {
+            if is_lint_ref_type(cx, ty) {
                 check_invalid_clippy_version_attribute(cx, item);
 
                 let expr = &cx.tcx.hir().body(body_id).value;
-                let fields;
-                if is_lint_ref_ty {
-                    if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
-                        && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind
-                    {
-                        fields = struct_fields;
-                    } else {
-                        return;
-                    }
-                } else if let ExprKind::Struct(_, struct_fields, _) = expr.kind {
-                    fields = struct_fields;
+                let fields = if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
+                    && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind
+                {
+                    struct_fields
                 } else {
                     return;
-                }
+                };
 
                 let field = fields
                     .iter()
@@ -175,25 +124,15 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                 }) = field.expr.kind
                 {
                     let sym_str = sym.as_str();
-                    if is_lint_ref_ty {
-                        if sym_str == "default lint description" {
-                            span_lint(
-                                cx,
-                                DEFAULT_LINT,
-                                item.span,
-                                format!("the lint `{}` has the default lint description", item.ident.name),
-                            );
-                        }
-
-                        self.declared_lints.insert(item.ident.name, item.span);
-                    } else if sym_str == "default deprecation note" {
+                    if sym_str == "default lint description" {
                         span_lint(
                             cx,
-                            DEFAULT_DEPRECATION_REASON,
+                            DEFAULT_LINT,
                             item.span,
-                            format!("the lint `{}` has the default deprecation reason", item.ident.name),
+                            format!("the lint `{}` has the default lint description", item.ident.name),
                         );
                     }
+                    self.declared_lints.insert(item.ident.name, item.span);
                 }
             }
         } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 1c149f20456..57f45aa3e48 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -7,13 +7,12 @@
 //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
 //! a simple mistake)
 
-use crate::renamed_lints::RENAMED_LINTS;
 use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type};
 use clippy_config::{get_configuration_metadata, ClippyConfiguration};
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
-use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
+use clippy_utils::{last_path_segment, match_function_call, match_path, paths};
 use itertools::Itertools;
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
@@ -85,11 +84,6 @@ const SUGGESTION_DIAG_METHODS: [(&str, bool); 9] = [
     ("tool_only_multipart_suggestion", true),
     ("span_suggestions", true),
 ];
-const SUGGESTION_FUNCTIONS: [&[&str]; 2] = [
-    &["clippy_utils", "diagnostics", "multispan_sugg"],
-    &["clippy_utils", "diagnostics", "multispan_sugg_with_applicability"],
-];
-const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "ClippyDeprecatedLint"];
 
 /// The index of the applicability name of `paths::APPLICABILITY_VALUES`
 const APPLICABILITY_NAME_INDEX: usize = 2;
@@ -165,9 +159,9 @@ impl MetadataCollector {
     fn get_lint_configs(&self, lint_name: &str) -> Option<String> {
         self.config
             .iter()
-            .filter(|config| config.lints.iter().any(|lint| lint == lint_name))
+            .filter(|config| config.lints.iter().any(|&lint| lint == lint_name))
             .map(ToString::to_string)
-            .reduce(|acc, x| acc + &x)
+            .reduce(|acc, x| acc + "\n\n" + &x)
             .map(|configurations| {
                 format!(
                     r#"
@@ -216,6 +210,13 @@ impl Drop for MetadataCollector {
 
         let mut applicability_info = std::mem::take(&mut self.applicability_info);
 
+        // Add deprecated lints
+        self.lints.extend(
+            crate::deprecated_lints::DEPRECATED
+                .iter()
+                .zip(crate::deprecated_lints::DEPRECATED_VERSION)
+                .filter_map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)),
+        );
         // Mapping the final data
         let mut lints = std::mem::take(&mut self.lints).into_sorted_vec();
         for x in &mut lints {
@@ -261,7 +262,7 @@ Please use that command to update the file and do not edit it by hand.
 #[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)]
 struct LintMetadata {
     id: String,
-    id_span: SerializableSpan,
+    id_span: Option<SerializableSpan>,
     group: String,
     level: String,
     docs: String,
@@ -285,7 +286,7 @@ impl LintMetadata {
     ) -> Self {
         Self {
             id,
-            id_span,
+            id_span: Some(id_span),
             group,
             level: level.to_string(),
             version,
@@ -294,6 +295,29 @@ impl LintMetadata {
             former_ids: BTreeSet::new(),
         }
     }
+
+    fn new_deprecated(name: &str, reason: &str, version: &str) -> Option<Self> {
+        // The reason starts with a lowercase letter and end without a period.
+        // This needs to be fixed for the website.
+        let mut reason = reason.to_owned();
+        if let Some(reason) = reason.get_mut(0..1) {
+            reason.make_ascii_uppercase();
+        }
+        name.strip_prefix("clippy::").map(|name| Self {
+            id: name.into(),
+            id_span: None,
+            group: DEPRECATED_LINT_GROUP_STR.into(),
+            level: DEPRECATED_LINT_LEVEL.into(),
+            version: version.into(),
+            docs: format!(
+                "### What it does\n\n\
+                Nothing. This lint has been deprecated\n\n\
+                ### Deprecation reason\n\n{reason}.\n",
+            ),
+            applicability: None,
+            former_ids: BTreeSet::new(),
+        })
+    }
 }
 
 fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Path) {
@@ -564,24 +588,6 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
                     raw_docs,
                 ));
             }
-
-            if is_deprecated_lint(cx, ty)
-                // disallow check
-                && let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase()
-                // Metadata the little we can get from a deprecated lint
-                && let Some(raw_docs) = extract_attr_docs_or_lint(cx, item)
-            {
-                let version = get_lint_version(cx, item);
-
-                self.lints.push(LintMetadata::new(
-                    lint_name,
-                    SerializableSpan::from_item(cx, item),
-                    DEPRECATED_LINT_GROUP_STR.to_string(),
-                    DEPRECATED_LINT_LEVEL,
-                    version,
-                    raw_docs,
-                ));
-            }
         }
     }
 
@@ -684,6 +690,11 @@ fn cleanup_docs(docs_collection: &Vec<String>) -> String {
                     .find(|&s| !matches!(s, "" | "ignore" | "no_run" | "should_panic"))
                     // if no language is present, fill in "rust"
                     .unwrap_or("rust");
+                let len_diff = line.len() - line.trim_start().len();
+                if len_diff != 0 {
+                    // We put back the indentation.
+                    docs.push_str(&line[..len_diff]);
+                }
                 docs.push_str("```");
                 docs.push_str(lang);
 
@@ -766,16 +777,6 @@ fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> {
         .find_map(|(group_name, group_level)| (*group_name == lint_group).then_some(*group_level))
 }
 
-pub(super) fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
-    if let hir::TyKind::Path(ref path) = ty.kind {
-        if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) {
-            return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE);
-        }
-    }
-
-    false
-}
-
 fn collect_renames(lints: &mut Vec<LintMetadata>) {
     for lint in lints {
         let mut collected = String::new();
@@ -783,7 +784,7 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) {
 
         loop {
             if let Some(lint_name) = names.pop() {
-                for (k, v) in RENAMED_LINTS {
+                for (k, v) in crate::deprecated_lints::RENAMED {
                     if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX)
                         && name == lint_name
                         && let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX)
@@ -1055,33 +1056,21 @@ impl<'a, 'hir> Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
             return;
         }
 
-        match &expr.kind {
-            ExprKind::Call(fn_expr, _args) => {
-                let found_function = SUGGESTION_FUNCTIONS
-                    .iter()
-                    .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
-                if found_function {
-                    // These functions are all multi part suggestions
-                    self.add_single_span_suggestion();
-                }
-            },
-            ExprKind::MethodCall(path, recv, _, _arg_span) => {
-                let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv));
-                if match_type(self.cx, self_ty, &paths::DIAG) {
-                    let called_method = path.ident.name.as_str().to_string();
-                    for (method_name, is_multi_part) in &SUGGESTION_DIAG_METHODS {
-                        if *method_name == called_method {
-                            if *is_multi_part {
-                                self.add_multi_part_suggestion();
-                            } else {
-                                self.add_single_span_suggestion();
-                            }
-                            break;
+        if let ExprKind::MethodCall(path, recv, _, _arg_span) = &expr.kind {
+            let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv));
+            if match_type(self.cx, self_ty, &paths::DIAG) {
+                let called_method = path.ident.name.as_str().to_string();
+                for (method_name, is_multi_part) in &SUGGESTION_DIAG_METHODS {
+                    if *method_name == called_method {
+                        if *is_multi_part {
+                            self.add_multi_part_suggestion();
+                        } else {
+                            self.add_single_span_suggestion();
                         }
+                        break;
                     }
                 }
-            },
-            _ => {},
+            }
         }
 
         intravisit::walk_expr(self, expr);
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index a831234906b..228db14d1b7 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -3,7 +3,7 @@ use std::ops::ControlFlow;
 
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::is_copy;
@@ -159,7 +159,7 @@ impl UselessVec {
 
         let snippet = match *vec_args {
             higher::VecArgs::Repeat(elem, len) => {
-                if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) {
+                if let Some(Constant::Int(len_constant)) = ConstEvalCtxt::new(cx).eval(len) {
                     // vec![ty; N] works when ty is Clone, [ty; N] requires it to be Copy also
                     if !is_copy(cx, cx.typeck_results().expr_ty(elem)) {
                         return;
diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs
index 11dcceca7ab..63f3a5d7f83 100644
--- a/src/tools/clippy/clippy_lints/src/visibility.rs
+++ b/src/tools/clippy/clippy_lints/src/visibility.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{Item, VisibilityKind};
 use rustc_errors::Applicability;
@@ -85,14 +85,19 @@ impl EarlyLintPass for Visibility {
             if **path == kw::SelfLower
                 && let Some(false) = is_from_proc_macro(cx, item.vis.span)
             {
-                span_lint_and_sugg(
+                span_lint_and_then(
                     cx,
                     NEEDLESS_PUB_SELF,
                     item.vis.span,
                     format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }),
-                    "remove it",
-                    String::new(),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion_hidden(
+                            item.vis.span,
+                            "remove it",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
             }
 
@@ -101,14 +106,20 @@ impl EarlyLintPass for Visibility {
                 && let [.., last] = &*path.segments
                 && let Some(false) = is_from_proc_macro(cx, item.vis.span)
             {
-                span_lint_and_sugg(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     PUB_WITHOUT_SHORTHAND,
                     item.vis.span,
                     "usage of `pub` with `in`",
-                    "remove it",
-                    format!("pub({})", last.ident),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(
+                            item.vis.span,
+                            "remove it",
+                            format!("pub({})", last.ident),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
             }
 
@@ -116,14 +127,20 @@ impl EarlyLintPass for Visibility {
                 && let [.., last] = &*path.segments
                 && let Some(false) = is_from_proc_macro(cx, item.vis.span)
             {
-                span_lint_and_sugg(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     PUB_WITH_SHORTHAND,
                     item.vis.span,
                     "usage of `pub` without `in`",
-                    "add it",
-                    format!("pub(in {})", last.ident),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(
+                            item.vis.span,
+                            "add it",
+                            format!("pub(in {})", last.ident),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index 60d8a13d359..5eb207a0aed 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -36,8 +36,9 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv {
             // TODO - constant_simple does not fold many operations involving floats.
             // That's probably fine for this lint - it's pretty unlikely that someone would
             // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
-            && let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left)
-            && let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right)
+            && let ecx = ConstEvalCtxt::new(cx)
+            && let Some(lhs_value) = ecx.eval_simple(left)
+            && let Some(rhs_value) = ecx.eval_simple(right)
             // FIXME(f16_f128): add these types when eq is available on all platforms
             && (Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value)
             && (Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value)
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index f0c64fdd573..9fefd94d339 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -12,9 +12,6 @@ rustc-semver = "1.1"
 # FIXME(f16_f128): remove when no longer needed for parsing
 rustc_apfloat = "0.2.0"
 
-[features]
-deny-warnings = ["clippy_config/deny-warnings"]
-
 [package.metadata.rust-analyzer]
 # This crate uses #[feature(rustc_private)]
 rustc_private = true
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index de6ccfe476f..e907e4058e5 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -14,12 +14,13 @@ use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{alloc_range, Scalar};
 use rustc_middle::mir::ConstValue;
-use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy};
+use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::def_id::DefId;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Ident;
 use rustc_span::{sym, SyntaxContext};
 use rustc_target::abi::Size;
+use std::cell::Cell;
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
 use std::iter;
@@ -263,10 +264,10 @@ impl<'tcx> Constant<'tcx> {
     }
 
     /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
-    pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
+    pub fn int_value(&self, tcx: TyCtxt<'_>, val_type: Ty<'_>) -> Option<FullInt> {
         if let Constant::Int(const_int) = *self {
             match *val_type.kind() {
-                ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
+                ty::Int(ity) => Some(FullInt::S(sext(tcx, const_int, ity))),
                 ty::Uint(_) => Some(FullInt::U(const_int)),
                 _ => None,
             }
@@ -322,6 +323,7 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
 }
 
 /// The source of a constant value.
+#[derive(Clone, Copy)]
 pub enum ConstantSource {
     /// The value is determined solely from the expression.
     Local,
@@ -331,54 +333,11 @@ pub enum ConstantSource {
     CoreConstant,
 }
 impl ConstantSource {
-    pub fn is_local(&self) -> bool {
+    pub fn is_local(self) -> bool {
         matches!(self, Self::Local)
     }
 }
 
-/// Attempts to check whether the expression is a constant representing an empty slice, str, array,
-/// etc…
-pub fn constant_is_empty(lcx: &LateContext<'_>, e: &Expr<'_>) -> Option<bool> {
-    ConstEvalLateContext::new(lcx, lcx.typeck_results()).expr_is_empty(e)
-}
-
-/// Attempts to evaluate the expression as a constant.
-pub fn constant<'tcx>(
-    lcx: &LateContext<'tcx>,
-    typeck_results: &ty::TypeckResults<'tcx>,
-    e: &Expr<'_>,
-) -> Option<Constant<'tcx>> {
-    ConstEvalLateContext::new(lcx, typeck_results).expr(e)
-}
-
-/// Attempts to evaluate the expression as a constant.
-pub fn constant_with_source<'tcx>(
-    lcx: &LateContext<'tcx>,
-    typeck_results: &ty::TypeckResults<'tcx>,
-    e: &Expr<'_>,
-) -> Option<(Constant<'tcx>, ConstantSource)> {
-    let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results);
-    let res = ctxt.expr(e);
-    res.map(|x| (x, ctxt.source))
-}
-
-/// Attempts to evaluate an expression only if its value is not dependent on other items.
-pub fn constant_simple<'tcx>(
-    lcx: &LateContext<'tcx>,
-    typeck_results: &ty::TypeckResults<'tcx>,
-    e: &Expr<'_>,
-) -> Option<Constant<'tcx>> {
-    constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c))
-}
-
-pub fn constant_full_int<'tcx>(
-    lcx: &LateContext<'tcx>,
-    typeck_results: &ty::TypeckResults<'tcx>,
-    e: &Expr<'_>,
-) -> Option<FullInt> {
-    constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
-}
-
 #[derive(Copy, Clone, Debug, Eq)]
 pub enum FullInt {
     S(i128),
@@ -417,44 +376,87 @@ impl Ord for FullInt {
     }
 }
 
-pub struct ConstEvalLateContext<'a, 'tcx> {
-    lcx: &'a LateContext<'tcx>,
-    typeck_results: &'a ty::TypeckResults<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    source: ConstantSource,
-    args: GenericArgsRef<'tcx>,
+/// The context required to evaluate a constant expression.
+///
+/// This is currently limited to constant folding and reading the value of named constants.
+pub struct ConstEvalCtxt<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    typeck: &'tcx TypeckResults<'tcx>,
+    source: Cell<ConstantSource>,
 }
 
-impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
-    pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
+impl<'tcx> ConstEvalCtxt<'tcx> {
+    /// Creates the evaluation context from the lint context. This requires the lint context to be
+    /// in a body (i.e. `cx.enclosing_body.is_some()`).
+    pub fn new(cx: &LateContext<'tcx>) -> Self {
+        Self {
+            tcx: cx.tcx,
+            param_env: cx.param_env,
+            typeck: cx.typeck_results(),
+            source: Cell::new(ConstantSource::Local),
+        }
+    }
+
+    /// Creates an evaluation context.
+    pub fn with_env(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self {
         Self {
-            lcx,
-            typeck_results,
-            param_env: lcx.param_env,
-            source: ConstantSource::Local,
-            args: List::empty(),
+            tcx,
+            param_env,
+            typeck,
+            source: Cell::new(ConstantSource::Local),
+        }
+    }
+
+    /// Attempts to evaluate the expression and returns both the value and whether it's dependant on
+    /// other items.
+    pub fn eval_with_source(&self, e: &Expr<'_>) -> Option<(Constant<'tcx>, ConstantSource)> {
+        self.source.set(ConstantSource::Local);
+        self.expr(e).map(|c| (c, self.source.get()))
+    }
+
+    /// Attempts to evaluate the expression.
+    pub fn eval(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
+        self.expr(e)
+    }
+
+    /// Attempts to evaluate the expression without accessing other items.
+    pub fn eval_simple(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
+        match self.eval_with_source(e) {
+            Some((x, ConstantSource::Local)) => Some(x),
+            _ => None,
+        }
+    }
+
+    /// Attempts to evaluate the expression as an integer without accessing other items.
+    pub fn eval_full_int(&self, e: &Expr<'_>) -> Option<FullInt> {
+        match self.eval_with_source(e) {
+            Some((x, ConstantSource::Local)) => x.int_value(self.tcx, self.typeck.expr_ty(e)),
+            _ => None,
         }
     }
 
     /// Simple constant folding: Insert an expression, get a constant or none.
-    pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
+    fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
         match e.kind {
-            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
             ExprKind::DropTemps(e) => self.expr(e),
             ExprKind::Path(ref qpath) => {
-                let is_core_crate = if let Some(def_id) = self.lcx.qpath_res(qpath, e.hir_id()).opt_def_id() {
-                    self.lcx.tcx.crate_name(def_id.krate) == sym::core
+                let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
+                    self.tcx.crate_name(def_id.krate) == sym::core
                 } else {
                     false
                 };
-                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
-                    let result = mir_to_const(this.lcx, result)?;
+                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
+                    let result = mir_to_const(self_.tcx, result)?;
                     // If source is already Constant we wouldn't want to override it with CoreConstant
-                    this.source = if is_core_crate && !matches!(this.source, ConstantSource::Constant) {
-                        ConstantSource::CoreConstant
-                    } else {
-                        ConstantSource::Constant
-                    };
+                    self_.source.set(
+                        if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
+                            ConstantSource::CoreConstant
+                        } else {
+                            ConstantSource::Constant
+                        },
+                    );
                     Some(result)
                 })
             },
@@ -463,21 +465,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
                     None
                 } else {
-                    Some(lit_to_mir_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
+                    Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e)))
                 }
             },
             ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
             ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
             ExprKind::Repeat(value, _) => {
-                let n = match self.typeck_results.expr_ty(e).kind() {
-                    ty::Array(_, n) => n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)?,
+                let n = match self.typeck.expr_ty(e).kind() {
+                    ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?,
                     _ => span_bug!(e.span, "typeck error"),
                 };
                 self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
             },
             ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
-                UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
-                UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
+                UnOp::Not => self.constant_not(&o, self.typeck.expr_ty(e)),
+                UnOp::Neg => self.constant_negate(&o, self.typeck.expr_ty(e)),
                 UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
             }),
             ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
@@ -486,21 +488,16 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 // We only handle a few const functions for now.
                 if args.is_empty()
                     && let ExprKind::Path(qpath) = &callee.kind
-                    && let res = self.typeck_results.qpath_res(qpath, callee.hir_id)
-                    && let Some(def_id) = res.opt_def_id()
-                    && let def_path = self.lcx.get_def_path(def_id)
-                    && let def_path = def_path.iter().take(4).map(Symbol::as_str).collect::<Vec<_>>()
-                    && let ["core", "num", int_impl, "max_value"] = *def_path
+                    && let Some(did) = self.typeck.qpath_res(qpath, callee.hir_id).opt_def_id()
                 {
-                    let value = match int_impl {
-                        "<impl i8>" => i8::MAX as u128,
-                        "<impl i16>" => i16::MAX as u128,
-                        "<impl i32>" => i32::MAX as u128,
-                        "<impl i64>" => i64::MAX as u128,
-                        "<impl i128>" => i128::MAX as u128,
-                        _ => return None,
-                    };
-                    Some(Constant::Int(value))
+                    match self.tcx.get_diagnostic_name(did) {
+                        Some(sym::i8_legacy_fn_max_value) => Some(Constant::Int(i8::MAX as u128)),
+                        Some(sym::i16_legacy_fn_max_value) => Some(Constant::Int(i16::MAX as u128)),
+                        Some(sym::i32_legacy_fn_max_value) => Some(Constant::Int(i32::MAX as u128)),
+                        Some(sym::i64_legacy_fn_max_value) => Some(Constant::Int(i64::MAX as u128)),
+                        Some(sym::i128_legacy_fn_max_value) => Some(Constant::Int(i128::MAX as u128)),
+                        _ => None,
+                    }
                 } else {
                     None
                 }
@@ -512,9 +509,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 if let Some(Constant::Adt(constant)) = &self.expr(local_expr)
                     && let ty::Adt(adt_def, _) = constant.ty().kind()
                     && adt_def.is_struct()
-                    && let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field)
+                    && let Some(desired_field) = field_of_struct(*adt_def, self.tcx, *constant, field)
                 {
-                    mir_to_const(self.lcx, desired_field)
+                    mir_to_const(self.tcx, desired_field)
                 } else {
                     result
                 }
@@ -526,21 +523,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     /// Simple constant folding to determine if an expression is an empty slice, str, array, …
     /// `None` will be returned if the constness cannot be determined, or if the resolution
     /// leaves the local crate.
-    pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
+    pub fn eval_is_empty(&self, e: &Expr<'_>) -> Option<bool> {
         match e.kind {
-            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value),
-            ExprKind::DropTemps(e) => self.expr_is_empty(e),
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.eval_is_empty(self.tcx.hir().body(body).value),
+            ExprKind::DropTemps(e) => self.eval_is_empty(e),
             ExprKind::Path(ref qpath) => {
                 if !self
-                    .typeck_results
+                    .typeck
                     .qpath_res(qpath, e.hir_id)
                     .opt_def_id()
                     .is_some_and(DefId::is_local)
                 {
                     return None;
                 }
-                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
-                    mir_is_empty(this.lcx, result)
+                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
+                    mir_is_empty(self_.tcx, result)
                 })
             },
             ExprKind::Lit(lit) => {
@@ -556,8 +553,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
             },
             ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()),
             ExprKind::Repeat(..) => {
-                if let ty::Array(_, n) = self.typeck_results.expr_ty(e).kind() {
-                    Some(n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)? == 0)
+                if let ty::Array(_, n) = self.typeck.expr_ty(e).kind() {
+                    Some(n.try_eval_target_usize(self.tcx, self.param_env)? == 0)
                 } else {
                     span_bug!(e.span, "typeck error");
                 }
@@ -574,8 +571,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
             Int(value) => {
                 let value = !value;
                 match *ty.kind() {
-                    ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
-                    ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
+                    ty::Int(ity) => Some(Int(unsext(self.tcx, value as i128, ity))),
+                    ty::Uint(ity) => Some(Int(clip(self.tcx, value, ity))),
                     _ => None,
                 }
             },
@@ -590,7 +587,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 let ty::Int(ity) = *ty.kind() else { return None };
                 let (min, _) = ity.min_max()?;
                 // sign extend
-                let value = sext(self.lcx.tcx, value, ity);
+                let value = sext(self.tcx, value, ity);
 
                 // Applying unary - to the most negative value of any signed integer type panics.
                 if value == min {
@@ -599,7 +596,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 
                 let value = value.checked_neg()?;
                 // clear unused bits
-                Some(Int(unsext(self.lcx.tcx, value, ity)))
+                Some(Int(unsext(self.tcx, value, ity)))
             },
             F32(f) => Some(F32(-f)),
             F64(f) => Some(F64(-f)),
@@ -609,21 +606,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 
     /// Create `Some(Vec![..])` of all constants, unless there is any
     /// non-constant part.
-    fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
+    fn multi(&self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
         vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
     }
 
     /// Lookup a possibly constant expression from an `ExprKind::Path` and apply a function on it.
-    fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
+    fn fetch_path_and_apply<T, F>(&self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
     where
-        F: FnOnce(&mut Self, mir::Const<'tcx>) -> Option<T>,
+        F: FnOnce(&Self, mir::Const<'tcx>) -> Option<T>,
     {
-        let res = self.typeck_results.qpath_res(qpath, id);
+        let res = self.typeck.qpath_res(qpath, id);
         match res {
             Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
                 // Check if this constant is based on `cfg!(..)`,
                 // which is NOT constant for our purposes.
-                if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id)
+                if let Some(node) = self.tcx.hir().get_if_local(def_id)
                     && let Node::Item(Item {
                         kind: ItemKind::Const(.., body_id),
                         ..
@@ -632,20 +629,14 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                         kind: ExprKind::Lit(_),
                         span,
                         ..
-                    }) = self.lcx.tcx.hir_node(body_id.hir_id)
+                    }) = self.tcx.hir_node(body_id.hir_id)
                     && is_direct_expn_of(*span, "cfg").is_some()
                 {
                     return None;
                 }
 
-                let args = self.typeck_results.node_args(id);
-                let args = if self.args.is_empty() {
-                    args
-                } else {
-                    EarlyBinder::bind(args).instantiate(self.lcx.tcx, self.args)
-                };
+                let args = self.typeck.node_args(id);
                 let result = self
-                    .lcx
                     .tcx
                     .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
                     .ok()
@@ -656,7 +647,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'tcx>> {
+    fn index(&self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'tcx>> {
         let lhs = self.expr(lhs);
         let index = self.expr(index);
 
@@ -685,8 +676,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    /// A block can only yield a constant if it only has one constant expression.
-    fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
+    /// A block can only yield a constant if it has exactly one constant expression.
+    fn block(&self, block: &Block<'_>) -> Option<Constant<'tcx>> {
         if block.stmts.is_empty()
             && let Some(expr) = block.expr
         {
@@ -696,7 +687,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt)
                     && let expr_lo = expr_span.lo()
                     && expr_lo >= span.lo
-                    && let Some(src) = (span.lo..expr_lo).get_source_text(self.lcx)
+                    && let Some(src) = (span.lo..expr_lo).get_source_text(&self.tcx)
                     && let Some(src) = src.as_str()
                 {
                     use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace};
@@ -705,11 +696,11 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                         .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi))
                         .eq([OpenBrace])
                     {
-                        self.source = ConstantSource::Constant;
+                        self.source.set(ConstantSource::Constant);
                     }
                 } else {
                     // Unable to access the source. Assume a non-local dependency.
-                    self.source = ConstantSource::Constant;
+                    self.source.set(ConstantSource::Constant);
                 }
             }
 
@@ -719,7 +710,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant<'tcx>> {
+    fn ifthenelse(&self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant<'tcx>> {
         if let Some(Constant::Bool(b)) = self.expr(cond) {
             if b {
                 self.expr(then)
@@ -731,16 +722,16 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
+    fn binop(&self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
         let l = self.expr(left)?;
         let r = self.expr(right);
         match (l, r) {
-            (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
+            (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck.expr_ty_opt(left)?.kind() {
                 ty::Int(ity) => {
                     let (ty_min_value, _) = ity.min_max()?;
                     let bits = ity.bits();
-                    let l = sext(self.lcx.tcx, l, ity);
-                    let r = sext(self.lcx.tcx, r, ity);
+                    let l = sext(self.tcx, l, ity);
+                    let r = sext(self.tcx, r, ity);
 
                     // Using / or %, where the left-hand argument is the smallest integer of a signed integer type and
                     // the right-hand argument is -1 always panics, even with overflow-checks disabled
@@ -751,7 +742,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                         return None;
                     }
 
-                    let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity));
+                    let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
                     match op.node {
                         // When +, * or binary - create a value greater than the maximum value, or less than
                         // the minimum value that can be stored, it panics.
@@ -845,7 +836,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     }
 }
 
-pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
+pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
     let mir::Const::Val(val, _) = result else {
         // We only work on evaluated consts.
         return None;
@@ -863,13 +854,13 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
             _ => None,
         },
         (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
-            let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
+            let data = val.try_get_slice_bytes_for_diagnostics(tcx)?;
             String::from_utf8(data.to_owned()).ok().map(Constant::Str)
         },
         (_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)),
         (ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => {
-            let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
-            let len = len.try_to_target_usize(lcx.tcx)?;
+            let alloc = tcx.global_alloc(alloc_id).unwrap_memory().inner();
+            let len = len.try_to_target_usize(tcx)?;
             let ty::Float(flt) = sub_type.kind() else {
                 return None;
             };
@@ -877,7 +868,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
             let mut res = Vec::new();
             for idx in 0..len {
                 let range = alloc_range(offset + size * idx, size);
-                let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?;
+                let val = alloc.read_scalar(&tcx, range, /* read_provenance */ false).ok()?;
                 res.push(match flt {
                     FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)),
                     FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)),
@@ -891,7 +882,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
     }
 }
 
-fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<bool> {
+fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<bool> {
     let mir::Const::Val(val, _) = result else {
         // We only work on evaluated consts.
         return None;
@@ -902,26 +893,26 @@ fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Opti
                 if let ConstValue::Indirect { alloc_id, offset } = val {
                     // Get the length from the slice, using the same formula as
                     // [`ConstValue::try_get_slice_bytes_for_diagnostics`].
-                    let a = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
-                    let ptr_size = lcx.tcx.data_layout.pointer_size;
+                    let a = tcx.global_alloc(alloc_id).unwrap_memory().inner();
+                    let ptr_size = tcx.data_layout.pointer_size;
                     if a.size() < offset + 2 * ptr_size {
                         // (partially) dangling reference
                         return None;
                     }
                     let len = a
-                        .read_scalar(&lcx.tcx, alloc_range(offset + ptr_size, ptr_size), false)
+                        .read_scalar(&tcx, alloc_range(offset + ptr_size, ptr_size), false)
                         .ok()?
-                        .to_target_usize(&lcx.tcx)
+                        .to_target_usize(&tcx)
                         .ok()?;
                     Some(len == 0)
                 } else {
                     None
                 }
             },
-            ty::Array(_, len) => Some(len.try_to_target_usize(lcx.tcx)? == 0),
+            ty::Array(_, len) => Some(len.try_to_target_usize(tcx)? == 0),
             _ => None,
         },
-        (ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(lcx.tcx)? == 0),
+        (ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(tcx)? == 0),
         (ConstValue::ZeroSized, _) => Some(true),
         _ => None,
     }
@@ -929,12 +920,12 @@ fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Opti
 
 fn field_of_struct<'tcx>(
     adt_def: ty::AdtDef<'tcx>,
-    lcx: &LateContext<'tcx>,
+    tcx: TyCtxt<'tcx>,
     result: mir::Const<'tcx>,
     field: &Ident,
 ) -> Option<mir::Const<'tcx>> {
     if let mir::Const::Val(result, ty) = result
-        && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_user_output(result, ty)
+        && let Some(dc) = tcx.try_destructure_mir_constant_for_user_output(result, ty)
         && let Some(dc_variant) = dc.variant
         && let Some(variant) = adt_def.variants().get(dc_variant)
         && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 0641d37cd9a..4877fb65d37 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -330,32 +330,3 @@ pub fn span_lint_and_sugg<T: LintContext>(
         diag.span_suggestion(sp, help.into(), sugg, applicability);
     });
 }
-
-/// Create a suggestion made from several `span → replacement`.
-///
-/// Note: in the JSON format (used by `compiletest_rs`), the help message will
-/// appear once per
-/// replacement. In human-readable format though, it only appears once before
-/// the whole suggestion.
-pub fn multispan_sugg<I>(diag: &mut Diag<'_, ()>, help_msg: impl Into<SubdiagMessage>, sugg: I)
-where
-    I: IntoIterator<Item = (Span, String)>,
-{
-    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
-}
-
-/// Create a suggestion made from several `span → replacement`.
-///
-/// rustfix currently doesn't support the automatic application of suggestions with
-/// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141).
-/// Suggestions with multiple spans will be silently ignored.
-pub fn multispan_sugg_with_applicability<I>(
-    diag: &mut Diag<'_, ()>,
-    help_msg: impl Into<SubdiagMessage>,
-    applicability: Applicability,
-    sugg: I,
-) where
-    I: IntoIterator<Item = (Span, String)>,
-{
-    diag.multipart_suggestion(help_msg.into(), sugg.into_iter().collect(), applicability);
-}
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 6c40029a9de..a6dd12a28c5 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -9,7 +9,7 @@
 //!  - or-fun-call
 //!  - option-if-let-else
 
-use crate::consts::{constant, FullInt};
+use crate::consts::{ConstEvalCtxt, FullInt};
 use crate::ty::{all_predicates_of, is_copy};
 use crate::visitors::is_const_evaluatable;
 use rustc_hir::def::{DefKind, Res};
@@ -206,7 +206,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 },
 
                 // `-i32::MIN` panics with overflow checks
-                ExprKind::Unary(UnOp::Neg, right) if constant(self.cx, self.cx.typeck_results(), right).is_none() => {
+                ExprKind::Unary(UnOp::Neg, right) if ConstEvalCtxt::new(self.cx).eval(right).is_none() => {
                     self.eagerness |= NoChange;
                 },
 
@@ -232,7 +232,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 // Thus, we would realistically only delay the lint.
                 ExprKind::Binary(op, _, right)
                     if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr)
-                        && constant(self.cx, self.cx.typeck_results(), right).is_none() =>
+                        && ConstEvalCtxt::new(self.cx).eval(right).is_none() =>
                 {
                     self.eagerness |= NoChange;
                 },
@@ -240,9 +240,9 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 ExprKind::Binary(op, left, right)
                     if matches!(op.node, BinOpKind::Div | BinOpKind::Rem)
                         && let right_ty = self.cx.typeck_results().expr_ty(right)
-                        && let left = constant(self.cx, self.cx.typeck_results(), left)
-                        && let right = constant(self.cx, self.cx.typeck_results(), right)
-                            .and_then(|c| c.int_value(self.cx, right_ty))
+                        && let ecx = ConstEvalCtxt::new(self.cx)
+                        && let left = ecx.eval(left)
+                        && let right = ecx.eval(right).and_then(|c| c.int_value(self.cx.tcx, right_ty))
                         && matches!(
                             (left, right),
                             // `1 / x`: x might be zero
@@ -261,8 +261,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 ExprKind::Binary(op, left, right)
                     if matches!(op.node, BinOpKind::Add | BinOpKind::Sub | BinOpKind::Mul)
                         && !self.cx.typeck_results().expr_ty(e).is_floating_point()
-                        && (constant(self.cx, self.cx.typeck_results(), left).is_none()
-                            || constant(self.cx, self.cx.typeck_results(), right).is_none()) =>
+                        && let ecx = ConstEvalCtxt::new(self.cx)
+                        && (ecx.eval(left).is_none() || ecx.eval(right).is_none()) =>
                 {
                     self.eagerness |= NoChange;
                 },
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 277ba8427e0..8970b4d1229 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -2,7 +2,7 @@
 
 #![deny(clippy::missing_docs_in_private_items)]
 
-use crate::consts::{constant_simple, Constant};
+use crate::consts::{ConstEvalCtxt, Constant};
 use crate::ty::is_type_diagnostic_item;
 use crate::{is_expn_of, match_def_path, paths};
 
@@ -25,6 +25,8 @@ pub struct ForLoop<'tcx> {
     pub loop_id: HirId,
     /// entire `for` loop span
     pub span: Span,
+    /// label
+    pub label: Option<ast::Label>,
 }
 
 impl<'tcx> ForLoop<'tcx> {
@@ -33,7 +35,7 @@ impl<'tcx> ForLoop<'tcx> {
         if let ExprKind::DropTemps(e) = expr.kind
             && let ExprKind::Match(iterexpr, [arm], MatchSource::ForLoopDesugar) = e.kind
             && let ExprKind::Call(_, [arg]) = iterexpr.kind
-            && let ExprKind::Loop(block, ..) = arm.body.kind
+            && let ExprKind::Loop(block, label, ..) = arm.body.kind
             && let [stmt] = block.stmts
             && let hir::StmtKind::Expr(e) = stmt.kind
             && let ExprKind::Match(_, [_, some_arm], _) = e.kind
@@ -45,6 +47,7 @@ impl<'tcx> ForLoop<'tcx> {
                 body: some_arm.body,
                 loop_id: arm.body.hir_id,
                 span: expr.span.ctxt().outer_expn_data().call_site,
+                label,
             });
         }
         None
@@ -367,6 +370,7 @@ pub struct WhileLet<'hir> {
     pub let_expr: &'hir Expr<'hir>,
     /// `while let` loop body
     pub if_then: &'hir Expr<'hir>,
+    pub label: Option<ast::Label>,
     /// `while let PAT = EXPR`
     ///        ^^^^^^^^^^^^^^
     pub let_span: Span,
@@ -399,7 +403,7 @@ impl<'hir> WhileLet<'hir> {
                     }),
                 ..
             },
-            _,
+            label,
             LoopSource::While,
             _,
         ) = expr.kind
@@ -408,6 +412,7 @@ impl<'hir> WhileLet<'hir> {
                 let_pat,
                 let_expr,
                 if_then,
+                label,
                 let_span,
             });
         }
@@ -466,7 +471,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
                     return Some(VecInitKind::Default);
                 } else if name.ident.name.as_str() == "with_capacity" {
                     let arg = args.first()?;
-                    return match constant_simple(cx, cx.typeck_results(), arg) {
+                    return match ConstEvalCtxt::new(cx).eval_simple(arg) {
                         Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
                         _ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),
                     };
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 28178a61a93..f325e4eaf15 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1,4 +1,4 @@
-use crate::consts::constant_simple;
+use crate::consts::ConstEvalCtxt;
 use crate::macros::macro_backtrace;
 use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt};
 use crate::tokenize_with_text;
@@ -255,8 +255,8 @@ impl HirEqInterExpr<'_, '_, '_> {
         if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results
             && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right)
             && let (Some(l), Some(r)) = (
-                constant_simple(self.inner.cx, typeck_lhs, left),
-                constant_simple(self.inner.cx, typeck_rhs, right),
+                ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_lhs).eval_simple(left),
+                ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_rhs).eval_simple(right),
             )
             && l == r
         {
@@ -714,9 +714,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
     #[expect(clippy::too_many_lines)]
     pub fn hash_expr(&mut self, e: &Expr<'_>) {
-        let simple_const = self
-            .maybe_typeck_results
-            .and_then(|typeck_results| constant_simple(self.cx, typeck_results, e));
+        let simple_const = self.maybe_typeck_results.and_then(|typeck_results| {
+            ConstEvalCtxt::with_env(self.cx.tcx, self.cx.param_env, typeck_results).eval_simple(e)
+        });
 
         // const hashing may result in the same hash as some unrelated node, so add a sort of
         // discriminant depending on which path we're choosing next
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 1d5f1a2a2bb..28755ae0710 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -10,7 +10,6 @@
 #![feature(assert_matches)]
 #![feature(unwrap_infallible)]
 #![recursion_limit = "512"]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(
     clippy::missing_errors_doc,
     clippy::missing_panics_doc,
@@ -126,7 +125,7 @@ use rustc_span::{sym, Span};
 use rustc_target::abi::Integer;
 use visitors::Visitable;
 
-use crate::consts::{constant, mir_to_const, Constant};
+use crate::consts::{mir_to_const, ConstEvalCtxt, Constant};
 use crate::higher::Range;
 use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
 use crate::visitors::for_each_expr_without_closures;
@@ -211,20 +210,24 @@ pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {
     false
 }
 
-/// Returns `true` if the given `HirId` is inside a constant context.
+/// Checks if we are currently in a const context (e.g. `const fn`, `static`/`const` initializer).
 ///
-/// This is the same as `is_inside_always_const_context`, but also includes
-/// `const fn`.
+/// The current context is determined based on the current body which is set before calling a lint's
+/// entry point (any function on `LateLintPass`). If you need to check in a different context use
+/// `tcx.hir().is_inside_const_context(_)`.
 ///
-/// # Example
-///
-/// ```rust,ignore
-/// if in_constant(cx, expr.hir_id) {
-///     // Do something
-/// }
-/// ```
-pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
-    cx.tcx.hir().is_inside_const_context(id)
+/// Do not call this unless the `LateContext` has an enclosing body. For release build this case
+/// will safely return `false`, but debug builds will ICE. Note that `check_expr`, `check_block`,
+/// `check_pat` and a few other entry points will always have an enclosing body. Some entry points
+/// like `check_path` or `check_ty` may or may not have one.
+pub fn is_in_const_context(cx: &LateContext<'_>) -> bool {
+    debug_assert!(cx.enclosing_body.is_some(), "`LateContext` has no enclosing body");
+    cx.enclosing_body.is_some_and(|id| {
+        cx.tcx
+            .hir()
+            .body_const_context(cx.tcx.hir().body_owner_def_id(id))
+            .is_some()
+    })
 }
 
 /// Returns `true` if the given `HirId` is inside an always constant context.
@@ -589,9 +592,8 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<It
         "u128" => SimplifiedType::Uint(UintTy::U128),
         "f32" => SimplifiedType::Float(FloatTy::F32),
         "f64" => SimplifiedType::Float(FloatTy::F64),
-        #[allow(trivial_casts)]
         _ => {
-            return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_])
+            return Result::<&[_], rustc_errors::ErrorGuaranteed>::Ok(&[])
                 .into_iter()
                 .flatten()
                 .copied();
@@ -1579,8 +1581,8 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
             if let rustc_ty::Adt(_, subst) = ty.kind()
                 && let bnd_ty = subst.type_at(0)
                 && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
-                && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, bnd_ty, cx.tcx))
-                && let Some(start_const) = constant(cx, cx.typeck_results(), start)
+                && let Some(min_const) = mir_to_const(cx.tcx, Const::from_ty_const(min_val, bnd_ty, cx.tcx))
+                && let Some(start_const) = ConstEvalCtxt::new(cx).eval(start)
             {
                 start_const == min_const
             } else {
@@ -1592,8 +1594,8 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
                 if let rustc_ty::Adt(_, subst) = ty.kind()
                     && let bnd_ty = subst.type_at(0)
                     && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
-                    && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, bnd_ty, cx.tcx))
-                    && let Some(end_const) = constant(cx, cx.typeck_results(), end)
+                    && let Some(max_const) = mir_to_const(cx.tcx, Const::from_ty_const(max_val, bnd_ty, cx.tcx))
+                    && let Some(end_const) = ConstEvalCtxt::new(cx).eval(end)
                 {
                     end_const == max_const
                 } else {
@@ -1624,7 +1626,9 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
         return true;
     }
     let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id);
-    if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
+    if let Some(Constant::Int(v)) =
+        ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(enclosing_body), cx.tcx.typeck(enclosing_body)).eval(e)
+    {
         return value == v;
     }
     false
@@ -2927,6 +2931,7 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprU
             moved_before_use,
             same_ctxt,
         },
+        #[allow(unreachable_patterns)]
         Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
         None => ExprUseCtxt {
             node: Node::Crate(cx.tcx.hir().root_module()),
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index d5a3d8b9e5a..684c645c199 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -16,7 +16,6 @@ pub const BINARYHEAP_ITER: [&str; 5] = ["alloc", "collections", "binary_heap", "
 pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
 pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
 pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
-pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
 pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
 pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index f206b2ceebc..553af913ef9 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -142,7 +142,7 @@ fn check_rvalue<'tcx>(
                 // We cannot allow this for now.
                 return Err((span, "unsizing casts are only allowed for references right now".into()));
             };
-            let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
+            let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, tcx.param_env(def_id));
             if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
                 check_operand(tcx, op, span, body, msrv)?;
                 // Casting/coercing things to slices is fine.
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 496c8f5b553..96dd3c55d37 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -6,7 +6,8 @@ use rustc_ast::{LitKind, StrStyle};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
-use rustc_lint::{LateContext, LintContext};
+use rustc_lint::{EarlyContext, LateContext};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::source_map::{original_sp, SourceMap};
 use rustc_span::{
@@ -17,6 +18,30 @@ use std::borrow::Cow;
 use std::fmt;
 use std::ops::Range;
 
+pub trait HasSession {
+    fn sess(&self) -> &Session;
+}
+impl HasSession for Session {
+    fn sess(&self) -> &Session {
+        self
+    }
+}
+impl HasSession for TyCtxt<'_> {
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+}
+impl HasSession for EarlyContext<'_> {
+    fn sess(&self) -> &Session {
+        ::rustc_lint::LintContext::sess(self)
+    }
+}
+impl HasSession for LateContext<'_> {
+    fn sess(&self) -> &Session {
+        self.tcx.sess()
+    }
+}
+
 /// Conversion of a value into the range portion of a `Span`.
 pub trait SpanRange: Sized {
     fn into_range(self) -> Range<BytePos>;
@@ -71,19 +96,19 @@ impl IntoSpan for Range<BytePos> {
 pub trait SpanRangeExt: SpanRange {
     /// Gets the source file, and range in the file, of the given span. Returns `None` if the span
     /// extends through multiple files, or is malformed.
-    fn get_source_text(self, cx: &impl LintContext) -> Option<SourceFileRange> {
+    fn get_source_text(self, cx: &impl HasSession) -> Option<SourceFileRange> {
         get_source_text(cx.sess().source_map(), self.into_range())
     }
 
     /// Calls the given function with the source text referenced and returns the value. Returns
     /// `None` if the source text cannot be retrieved.
-    fn with_source_text<T>(self, cx: &impl LintContext, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> {
+    fn with_source_text<T>(self, cx: &impl HasSession, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> {
         with_source_text(cx.sess().source_map(), self.into_range(), f)
     }
 
     /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the
     /// source text cannot be retrieved.
-    fn check_source_text(self, cx: &impl LintContext, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool {
+    fn check_source_text(self, cx: &impl HasSession, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool {
         self.with_source_text(cx, pred).unwrap_or(false)
     }
 
@@ -91,7 +116,7 @@ pub trait SpanRangeExt: SpanRange {
     /// and returns the value. Returns `None` if the source text cannot be retrieved.
     fn with_source_text_and_range<T>(
         self,
-        cx: &impl LintContext,
+        cx: &impl HasSession,
         f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T,
     ) -> Option<T> {
         with_source_text_and_range(cx.sess().source_map(), self.into_range(), f)
@@ -104,30 +129,30 @@ pub trait SpanRangeExt: SpanRange {
     /// The new range must reside within the same source file.
     fn map_range(
         self,
-        cx: &impl LintContext,
+        cx: &impl HasSession,
         f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>,
     ) -> Option<Range<BytePos>> {
         map_range(cx.sess().source_map(), self.into_range(), f)
     }
 
     /// Extends the range to include all preceding whitespace characters.
-    fn with_leading_whitespace(self, cx: &impl LintContext) -> Range<BytePos> {
+    fn with_leading_whitespace(self, cx: &impl HasSession) -> Range<BytePos> {
         with_leading_whitespace(cx.sess().source_map(), self.into_range())
     }
 
     /// Trims the leading whitespace from the range.
-    fn trim_start(self, cx: &impl LintContext) -> Range<BytePos> {
+    fn trim_start(self, cx: &impl HasSession) -> Range<BytePos> {
         trim_start(cx.sess().source_map(), self.into_range())
     }
 
     /// Writes the referenced source text to the given writer. Will return `Err` if the source text
     /// could not be retrieved.
-    fn write_source_text_to(self, cx: &impl LintContext, dst: &mut impl fmt::Write) -> fmt::Result {
+    fn write_source_text_to(self, cx: &impl HasSession, dst: &mut impl fmt::Write) -> fmt::Result {
         write_source_text_to(cx.sess().source_map(), self.into_range(), dst)
     }
 
     /// Extracts the referenced source text as an owned string.
-    fn source_text_to_string(self, cx: &impl LintContext) -> Option<String> {
+    fn source_text_to_string(self, cx: &impl HasSession) -> Option<String> {
         self.with_source_text(cx, ToOwned::to_owned)
     }
 }
@@ -227,15 +252,15 @@ impl SourceFileRange {
 }
 
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
-pub fn expr_block<T: LintContext>(
-    cx: &T,
+pub fn expr_block(
+    sess: &impl HasSession,
     expr: &Expr<'_>,
     outer: SyntaxContext,
     default: &str,
     indent_relative_to: Option<Span>,
     app: &mut Applicability,
 ) -> String {
-    let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app);
+    let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app);
     if !from_macro
         && let ExprKind::Block(block, _) = expr.kind
         && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
@@ -260,13 +285,13 @@ pub fn expr_block<T: LintContext>(
 ///     let x = ();
 /// //  ^^^^^^^^^^
 /// ```
-pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span {
-    first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
+pub fn first_line_of_span(sess: &impl HasSession, span: Span) -> Span {
+    first_char_in_first_line(sess, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
 }
 
-fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> {
-    let line_span = line_span(cx, span);
-    snippet_opt(cx, line_span).and_then(|snip| {
+fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option<BytePos> {
+    let line_span = line_span(sess, span);
+    snippet_opt(sess, line_span).and_then(|snip| {
         snip.find(|c: char| !c.is_whitespace())
             .map(|pos| line_span.lo() + BytePos::from_usize(pos))
     })
@@ -281,9 +306,9 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
 ///        let x = ();
 /// // ^^^^^^^^^^^^^^
 /// ```
-fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
+fn line_span(sess: &impl HasSession, span: Span) -> Span {
     let span = original_sp(span, DUMMY_SP);
-    let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap();
+    let SourceFileAndLine { sf, line } = sess.sess().source_map().lookup_line(span.lo()).unwrap();
     let line_start = sf.lines()[line];
     let line_start = sf.absolute_position(line_start);
     span.with_lo(line_start)
@@ -297,13 +322,13 @@ fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
 ///     let x = ();
 /// //          ^^ -- will return 4
 /// ```
-pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
-    snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
+pub fn indent_of(sess: &impl HasSession, span: Span) -> Option<usize> {
+    snippet_opt(sess, line_span(sess, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
 }
 
 /// Gets a snippet of the indentation of the line of a span
-pub fn snippet_indent<T: LintContext>(cx: &T, span: Span) -> Option<String> {
-    snippet_opt(cx, line_span(cx, span)).map(|mut s| {
+pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> {
+    snippet_opt(sess, line_span(sess, span)).map(|mut s| {
         let len = s.len() - s.trim_start().len();
         s.truncate(len);
         s
@@ -315,8 +340,8 @@ pub fn snippet_indent<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 // sources that the user has no control over.
 // For some reason these attributes don't have any expansion info on them, so
 // we have to check it this way until there is a better way.
-pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool {
-    if let Some(snippet) = snippet_opt(cx, span) {
+pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool {
+    if let Some(snippet) = snippet_opt(sess, span) {
         if snippet.is_empty() {
             return false;
         }
@@ -407,8 +432,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>,
 /// snippet(cx, span1, "..") // -> "value"
 /// snippet(cx, span2, "..") // -> "Vec::new()"
 /// ```
-pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
-    snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
+pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> {
+    snippet_opt(sess, span).map_or_else(|| Cow::Borrowed(default), From::from)
 }
 
 /// Same as [`snippet`], but it adapts the applicability level by following rules:
@@ -417,13 +442,13 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<
 /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
 /// - If the default value is used and the applicability level is `MachineApplicable`, change it to
 ///   `HasPlaceholders`
-pub fn snippet_with_applicability<'a, T: LintContext>(
-    cx: &T,
+pub fn snippet_with_applicability<'a>(
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     applicability: &mut Applicability,
 ) -> Cow<'a, str> {
-    snippet_with_applicability_sess(cx.sess(), span, default, applicability)
+    snippet_with_applicability_sess(sess.sess(), span, default, applicability)
 }
 
 fn snippet_with_applicability_sess<'a>(
@@ -435,7 +460,7 @@ fn snippet_with_applicability_sess<'a>(
     if *applicability != Applicability::Unspecified && span.from_expansion() {
         *applicability = Applicability::MaybeIncorrect;
     }
-    snippet_opt_sess(sess, span).map_or_else(
+    snippet_opt(sess, span).map_or_else(
         || {
             if *applicability == Applicability::MachineApplicable {
                 *applicability = Applicability::HasPlaceholders;
@@ -447,12 +472,8 @@ fn snippet_with_applicability_sess<'a>(
 }
 
 /// Converts a span to a code snippet. Returns `None` if not available.
-pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option<String> {
-    snippet_opt_sess(cx.sess(), span)
-}
-
-fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
-    sess.source_map().span_to_snippet(span).ok()
+pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option<String> {
+    sess.sess().source_map().span_to_snippet(span).ok()
 }
 
 /// Converts a span (from a block) to a code snippet if available, otherwise use default.
@@ -489,41 +510,41 @@ fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
 ///     } // aligned with `if`
 /// ```
 /// Note that the first line of the snippet always has 0 indentation.
-pub fn snippet_block<'a, T: LintContext>(
-    cx: &T,
+pub fn snippet_block<'a>(
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     indent_relative_to: Option<Span>,
 ) -> Cow<'a, str> {
-    let snip = snippet(cx, span, default);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let snip = snippet(sess, span, default);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     reindent_multiline(snip, true, indent)
 }
 
 /// Same as `snippet_block`, but adapts the applicability level by the rules of
 /// `snippet_with_applicability`.
 pub fn snippet_block_with_applicability<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     indent_relative_to: Option<Span>,
     applicability: &mut Applicability,
 ) -> Cow<'a, str> {
-    let snip = snippet_with_applicability(cx, span, default, applicability);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let snip = snippet_with_applicability(sess, span, default, applicability);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     reindent_multiline(snip, true, indent)
 }
 
 pub fn snippet_block_with_context<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     outer: SyntaxContext,
     default: &'a str,
     indent_relative_to: Option<Span>,
     app: &mut Applicability,
 ) -> (Cow<'a, str>, bool) {
-    let (snip, from_macro) = snippet_with_context(cx, span, outer, default, app);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     (reindent_multiline(snip, true, indent), from_macro)
 }
 
@@ -537,13 +558,13 @@ pub fn snippet_block_with_context<'a>(
 ///
 /// This will also return whether or not the snippet is a macro call.
 pub fn snippet_with_context<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     outer: SyntaxContext,
     default: &'a str,
     applicability: &mut Applicability,
 ) -> (Cow<'a, str>, bool) {
-    snippet_with_context_sess(cx.sess(), span, outer, default, applicability)
+    snippet_with_context_sess(sess.sess(), span, outer, default, applicability)
 }
 
 fn snippet_with_context_sess<'a>(
@@ -661,15 +682,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
 /// writeln!(o, "")   ->   writeln!(o, "")
 ///             ^^                   ^^^^
 /// ```
-pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
-    let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true);
+pub fn expand_past_previous_comma(sess: &impl HasSession, span: Span) -> Span {
+    let extended = sess.sess().source_map().span_extend_to_prev_char(span, ',', true);
     extended.with_lo(extended.lo() - BytePos(1))
 }
 
 /// Converts `expr` to a `char` literal if it's a `str` literal containing a single
 /// character (or a single byte with `ascii_only`)
 pub fn str_literal_to_char_literal(
-    cx: &LateContext<'_>,
+    sess: &impl HasSession,
     expr: &Expr<'_>,
     applicability: &mut Applicability,
     ascii_only: bool,
@@ -684,7 +705,7 @@ pub fn str_literal_to_char_literal(
         }
         && len == 1
     {
-        let snip = snippet_with_applicability(cx, expr.span, string, applicability);
+        let snip = snippet_with_applicability(sess, expr.span, string, applicability);
         let ch = if let StrStyle::Raw(nhash) = style {
             let nhash = nhash as usize;
             // for raw string: r##"a"##
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 812fb647fda..bd48990aea9 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -525,19 +525,6 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
 }
 
-/// Peels off all references on the type. Returns the underlying type and the number of references
-/// removed.
-pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
-    fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
-        if let ty::Ref(_, ty, _) = ty.kind() {
-            peel(*ty, count + 1)
-        } else {
-            (ty, count)
-        }
-    }
-    peel(ty, 0)
-}
-
 /// Peels off all references on the type. Returns the underlying type, the number of references
 /// removed, and whether the pointer is ultimately mutable or not.
 pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 7066c9ad2b9..2a5d3536ff6 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -1,6 +1,7 @@
 use crate::ty::needs_ordered_drop;
 use crate::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
+use rustc_ast::visit::{try_visit, VisitorResult};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor};
@@ -50,16 +51,17 @@ impl Continue for Descend {
 /// A type which can be visited.
 pub trait Visitable<'tcx> {
     /// Calls the corresponding `visit_*` function on the visitor.
-    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result;
 }
 impl<'tcx, T> Visitable<'tcx> for &'tcx [T]
 where
     &'tcx T: Visitable<'tcx>,
 {
-    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result {
         for x in self {
-            x.visit(visitor);
+            try_visit!(x.visit(visitor));
         }
+        V::Result::output()
     }
 }
 impl<'tcx, A, B> Visitable<'tcx> for (A, B)
@@ -67,27 +69,28 @@ where
     A: Visitable<'tcx>,
     B: Visitable<'tcx>,
 {
-    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result {
         let (a, b) = self;
-        a.visit(visitor);
-        b.visit(visitor);
+        try_visit!(a.visit(visitor));
+        b.visit(visitor)
     }
 }
 impl<'tcx, T> Visitable<'tcx> for Option<T>
 where
     T: Visitable<'tcx>,
 {
-    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result {
         if let Some(x) = self {
-            x.visit(visitor);
+            try_visit!(x.visit(visitor));
         }
+        V::Result::output()
     }
 }
 macro_rules! visitable_ref {
     ($t:ident, $f:ident) => {
         impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
-            fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
-                visitor.$f(self);
+            fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result {
+                visitor.$f(self)
             }
         }
     };
@@ -104,45 +107,37 @@ pub fn for_each_expr_without_closures<'tcx, B, C: Continue>(
     node: impl Visitable<'tcx>,
     f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
 ) -> Option<B> {
-    struct V<B, F> {
+    struct V<F> {
         f: F,
-        res: Option<B>,
     }
-    impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<B, F> {
-        type Result = ControlFlow<()>;
+    impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<F> {
+        type Result = ControlFlow<B>;
 
-        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> ControlFlow<()> {
-            if self.res.is_some() {
-                return ControlFlow::Break(());
-            }
+        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> Self::Result {
             match (self.f)(e) {
                 ControlFlow::Continue(c) if c.descend() => walk_expr(self, e),
-                ControlFlow::Break(b) => {
-                    self.res = Some(b);
-                    ControlFlow::Break(())
-                },
+                ControlFlow::Break(b) => ControlFlow::Break(b),
                 ControlFlow::Continue(_) => ControlFlow::Continue(()),
             }
         }
 
         // Avoid unnecessary `walk_*` calls.
-        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> ControlFlow<()> {
+        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result {
             ControlFlow::Continue(())
         }
-        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> ControlFlow<()> {
+        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result {
             ControlFlow::Continue(())
         }
-        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> ControlFlow<()> {
+        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> Self::Result {
             ControlFlow::Continue(())
         }
         // Avoid monomorphising all `visit_*` functions.
-        fn visit_nested_item(&mut self, _: ItemId) -> ControlFlow<()> {
+        fn visit_nested_item(&mut self, _: ItemId) -> Self::Result {
             ControlFlow::Continue(())
         }
     }
-    let mut v = V { f, res: None };
-    node.visit(&mut v);
-    v.res
+    let mut v = V { f };
+    node.visit(&mut v).break_value()
 }
 
 /// Calls the given function once for each expression contained. This will enter bodies, but not
@@ -152,44 +147,47 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
     node: impl Visitable<'tcx>,
     f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
 ) -> Option<B> {
-    struct V<'tcx, B, F> {
+    struct V<'tcx, F> {
         tcx: TyCtxt<'tcx>,
         f: F,
-        res: Option<B>,
     }
-    impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<'tcx, B, F> {
+    impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<'tcx, F> {
         type NestedFilter = nested_filter::OnlyBodies;
+        type Result = ControlFlow<B>;
+
         fn nested_visit_map(&mut self) -> Self::Map {
             self.tcx.hir()
         }
 
-        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
-            if self.res.is_some() {
-                return;
-            }
+        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> Self::Result {
             match (self.f)(e) {
                 ControlFlow::Continue(c) if c.descend() => walk_expr(self, e),
-                ControlFlow::Break(b) => self.res = Some(b),
-                ControlFlow::Continue(_) => (),
+                ControlFlow::Break(b) => ControlFlow::Break(b),
+                ControlFlow::Continue(_) => ControlFlow::Continue(()),
             }
         }
 
         // Only walk closures
-        fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
+        fn visit_anon_const(&mut self, _: &'tcx AnonConst) -> Self::Result {
+            ControlFlow::Continue(())
+        }
         // Avoid unnecessary `walk_*` calls.
-        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {}
-        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {}
-        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {}
+        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result {
+            ControlFlow::Continue(())
+        }
+        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result {
+            ControlFlow::Continue(())
+        }
+        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> Self::Result {
+            ControlFlow::Continue(())
+        }
         // Avoid monomorphising all `visit_*` functions.
-        fn visit_nested_item(&mut self, _: ItemId) {}
+        fn visit_nested_item(&mut self, _: ItemId) -> Self::Result {
+            ControlFlow::Continue(())
+        }
     }
-    let mut v = V {
-        tcx: cx.tcx,
-        f,
-        res: None,
-    };
-    node.visit(&mut v);
-    v.res
+    let mut v = V { tcx: cx.tcx, f };
+    node.visit(&mut v).break_value()
 }
 
 /// returns `true` if expr contains match expr desugared from try
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 80106f683c2..31270241b0b 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -11,6 +11,3 @@ proc-macro = true
 itertools = "0.12"
 quote = "1.0.21"
 syn = "2.0"
-
-[features]
-deny-warnings = []
diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs
index 25b2fc9395c..ca070f6c250 100644
--- a/src/tools/clippy/declare_clippy_lint/src/lib.rs
+++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(let_chains)]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index 350418eeeb8..b0e4e3e3e57 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -25,6 +25,3 @@ tar = "0.4"
 toml = "0.7.3"
 ureq = { version = "2.2", features = ["json"] }
 walkdir = "2.3"
-
-[features]
-deny-warnings = []
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index 6bec1753fc7..bd4fcc5e337 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -33,13 +33,13 @@ pub(crate) struct LintcheckConfig {
     /// Runs cargo clippy --fix and checks if all suggestions apply
     #[clap(long, conflicts_with("max_jobs"))]
     pub fix: bool,
-    /// Apply a filter to only collect specified lints, this also overrides `allow` attributes
+    /// Apply a filter to only collect specified lints
     #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)]
     pub lint_filter: Vec<String>,
-    /// Set all lints to the "warn" lint level, even resitriction ones. Usually,
-    /// it's better to use `--filter` instead
+    /// Check all Clippy lints, by default only `clippy::all` and `clippy::pedantic` are checked.
+    /// Usually, it's better to use `--filter` instead
     #[clap(long, conflicts_with("lint_filter"))]
-    pub warn_all: bool,
+    pub all_lints: bool,
     /// Set the output format of the log file
     #[clap(long, short, default_value = "text")]
     pub format: OutputFormat,
diff --git a/src/tools/clippy/lintcheck/src/input.rs b/src/tools/clippy/lintcheck/src/input.rs
index 3b263674aa8..3383d50fa02 100644
--- a/src/tools/clippy/lintcheck/src/input.rs
+++ b/src/tools/clippy/lintcheck/src/input.rs
@@ -98,12 +98,12 @@ pub fn read_crates(toml_path: &Path) -> (Vec<CrateWithSource>, RecursiveOptions)
     let crate_list: SourceList =
         toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display()));
     // parse the hashmap of the toml file into a list of crates
-    let tomlcrates: Vec<TomlCrate> = crate_list.crates.into_values().collect();
+    let toml_crates: Vec<TomlCrate> = crate_list.crates.into_values().collect();
 
     // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
-    // multiple Cratesources)
+    // multiple CrateSources)
     let mut crate_sources = Vec::new();
-    for tk in tomlcrates {
+    for tk in toml_crates {
         if let Some(ref path) = tk.path {
             crate_sources.push(CrateWithSource {
                 name: tk.name.clone(),
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 0dd62ded293..acb6eaa5278 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -119,7 +119,8 @@ impl Crate {
         cmd.arg(if config.fix { "fix" } else { "check" })
             .arg("--quiet")
             .current_dir(&self.path)
-            .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__"));
+            .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__"))
+            .env("CLIPPY_DISABLE_DOCS_LINKS", "1");
 
         if let Some(server) = server {
             // `cargo clippy` is a wrapper around `cargo check` that mainly sets `RUSTC_WORKSPACE_WRAPPER` to
@@ -284,29 +285,24 @@ fn lintcheck(config: LintcheckConfig) {
     let (crates, recursive_options) = read_crates(&config.sources_toml_path);
 
     let counter = AtomicUsize::new(1);
-    let mut lint_level_args: Vec<String> = vec![];
+    let mut lint_level_args: Vec<String> = vec!["--cap-lints=allow".into()];
     if config.lint_filter.is_empty() {
-        lint_level_args.push("--cap-lints=warn".to_string());
-
-        // Set allow-by-default to warn
-        if config.warn_all {
-            [
+        let groups = if config.all_lints {
+            &[
+                "clippy::all",
                 "clippy::cargo",
                 "clippy::nursery",
                 "clippy::pedantic",
                 "clippy::restriction",
-            ]
+            ][..]
+        } else {
+            &["clippy::all", "clippy::pedantic"]
+        };
+        groups
             .iter()
-            .map(|group| format!("--warn={group}"))
+            .map(|group| format!("--force-warn={group}"))
             .collect_into(&mut lint_level_args);
-        } else {
-            ["clippy::cargo", "clippy::pedantic"]
-                .iter()
-                .map(|group| format!("--warn={group}"))
-                .collect_into(&mut lint_level_args);
-        }
     } else {
-        lint_level_args.push("--cap-lints=allow".to_string());
         config
             .lint_filter
             .iter()
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 69fb11a4824..5fbe4e544a9 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2024-07-25"
+channel = "nightly-2024-08-08"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/rustc_tools_util/Cargo.toml b/src/tools/clippy/rustc_tools_util/Cargo.toml
index 877049ae7d0..37b592da132 100644
--- a/src/tools/clippy/rustc_tools_util/Cargo.toml
+++ b/src/tools/clippy/rustc_tools_util/Cargo.toml
@@ -10,6 +10,3 @@ categories = ["development-tools"]
 edition = "2018"
 
 [dependencies]
-
-[features]
-deny-warnings = []
diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs
index 4c1d8c3733d..2cc38130472 100644
--- a/src/tools/clippy/rustc_tools_util/src/lib.rs
+++ b/src/tools/clippy/rustc_tools_util/src/lib.rs
@@ -1,4 +1,4 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+use std::str;
 
 /// This macro creates the version string during compilation from the
 /// current environment
@@ -101,49 +101,46 @@ impl std::fmt::Debug for VersionInfo {
 
 #[must_use]
 pub fn get_commit_hash() -> Option<String> {
-    std::process::Command::new("git")
-        .args(["rev-parse", "--short", "HEAD"])
+    let output = std::process::Command::new("git")
+        .args(["rev-parse", "HEAD"])
         .output()
-        .ok()
-        .and_then(|r| String::from_utf8(r.stdout).ok())
+        .ok()?;
+    let mut stdout = output.status.success().then_some(output.stdout)?;
+    stdout.truncate(10);
+    String::from_utf8(stdout).ok()
 }
 
 #[must_use]
 pub fn get_commit_date() -> Option<String> {
-    std::process::Command::new("git")
+    let output = std::process::Command::new("git")
         .args(["log", "-1", "--date=short", "--pretty=format:%cd"])
         .output()
-        .ok()
-        .and_then(|r| String::from_utf8(r.stdout).ok())
+        .ok()?;
+    let stdout = output.status.success().then_some(output.stdout)?;
+    String::from_utf8(stdout).ok()
 }
 
 #[must_use]
 pub fn get_channel() -> String {
-    match std::env::var("CFG_RELEASE_CHANNEL") {
-        Ok(channel) => channel,
-        Err(_) => {
-            // if that failed, try to ask rustc -V, do some parsing and find out
-            match std::process::Command::new("rustc")
-                .arg("-V")
-                .output()
-                .ok()
-                .and_then(|r| String::from_utf8(r.stdout).ok())
-            {
-                Some(rustc_output) => {
-                    if rustc_output.contains("beta") {
-                        String::from("beta")
-                    } else if rustc_output.contains("stable") {
-                        String::from("stable")
-                    } else {
-                        // default to nightly if we fail to parse
-                        String::from("nightly")
-                    }
-                },
-                // default to nightly
-                None => String::from("nightly"),
+    if let Ok(channel) = std::env::var("CFG_RELEASE_CHANNEL") {
+        return channel;
+    }
+
+    // if that failed, try to ask rustc -V, do some parsing and find out
+    if let Ok(output) = std::process::Command::new("rustc").arg("-V").output() {
+        if output.status.success() {
+            if let Ok(rustc_output) = str::from_utf8(&output.stdout) {
+                if rustc_output.contains("beta") {
+                    return String::from("beta");
+                } else if rustc_output.contains("stable") {
+                    return String::from("stable");
+                }
             }
-        },
+        }
     }
+
+    // default to nightly
+    String::from("nightly")
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 3fafe2427a2..0ac3f35b446 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -2,7 +2,6 @@
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(rustc_private)]
 #![feature(let_chains)]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 // warn on rustc internal lints
@@ -151,7 +150,6 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
             let conf = clippy_config::Conf::read(sess, &conf_path);
             clippy_lints::register_lints(lint_store, conf);
             clippy_lints::register_pre_expansion_lints(lint_store, conf);
-            clippy_lints::register_renamed(lint_store);
         }));
 
         // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index 30beaae34d2..c9af2138a72 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
diff --git a/src/tools/clippy/tests/check-fmt.rs b/src/tools/clippy/tests/check-fmt.rs
index e106583de4a..cd3fed896c2 100644
--- a/src/tools/clippy/tests/check-fmt.rs
+++ b/src/tools/clippy/tests/check-fmt.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use std::path::PathBuf;
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 4e5120406b0..c7080e5dcdc 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
@@ -208,7 +207,8 @@ fn run_ui_toml() {
     ui_test::run_tests_generic(
         vec![config],
         ui_test::default_file_filter,
-        |config, path, _file_contents| {
+        |config, file_contents| {
+            let path = file_contents.span().file;
             config
                 .program
                 .envs
@@ -260,7 +260,7 @@ fn run_ui_cargo() {
             path.ends_with("Cargo.toml")
                 .then(|| ui_test::default_any_file_filter(path, config) && !ignored_32bit(path))
         },
-        |_config, _path, _file_contents| {},
+        |_config, _file_contents| {},
         status_emitter::Text::from(args.format),
     )
     .unwrap();
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index c8a761bf509..8d10d5e7161 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -3,7 +3,6 @@
 //!
 //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
 
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use itertools::Itertools;
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index 77b7bb6a7bf..13cf36823c5 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -8,7 +8,6 @@
 //! Clippy doesn't produce an ICE. Lint warnings are ignored by this test.
 
 #![cfg(feature = "integration")]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use std::env;
diff --git a/src/tools/clippy/tests/lint_message_convention.rs b/src/tools/clippy/tests/lint_message_convention.rs
index 6ce7e44474d..7ed1f485c1c 100644
--- a/src/tools/clippy/tests/lint_message_convention.rs
+++ b/src/tools/clippy/tests/lint_message_convention.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use std::ffi::OsStr;
diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs
index 141c11ddb47..a8225d037e8 100644
--- a/src/tools/clippy/tests/missing-test-files.rs
+++ b/src/tools/clippy/tests/missing-test-files.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::assertions_on_constants)]
 #![feature(path_file_prefix)]
diff --git a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs b/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs
deleted file mode 100644
index c8961d5e1f0..00000000000
--- a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-#![deny(clippy::internal)]
-#![feature(rustc_private)]
-
-#[macro_use]
-extern crate clippy_lints;
-use clippy_lints::deprecated_lints::ClippyDeprecatedLint;
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// TODO
-    #[clippy::version = "1.63.0"]
-    pub COOL_LINT_DEFAULT,
-    "default deprecation note"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been replaced by `cooler_lint`
-    #[clippy::version = "1.63.0"]
-    pub COOL_LINT,
-    "this lint has been replaced by `cooler_lint`"
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr b/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr
deleted file mode 100644
index 3b7c747c23f..00000000000
--- a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: the lint `COOL_LINT_DEFAULT` has the default deprecation reason
-  --> tests/ui-internal/default_deprecation_reason.rs:8:1
-   |
-LL | / declare_deprecated_lint! {
-LL | |     /// ### What it does
-LL | |     /// Nothing. This lint has been deprecated.
-LL | |     ///
-...  |
-LL | |     "default deprecation note"
-LL | | }
-   | |_^
-   |
-note: the lint level is defined here
-  --> tests/ui-internal/default_deprecation_reason.rs:1:9
-   |
-LL | #![deny(clippy::internal)]
-   |         ^^^^^^^^^^^^^^^^
-   = note: `#[deny(clippy::default_deprecation_reason)]` implied by `#[deny(clippy::internal)]`
-   = note: this error originates in the macro `declare_deprecated_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
index 4375f324aca..858aab528a9 100644
--- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
+++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
@@ -1,15 +1,19 @@
 //@aux-build:../../ui/auxiliary/proc_macros.rs
 #![rustfmt::skip]
 #![feature(custom_inner_attributes)]
-#![allow(unused)]
-#![allow(clippy::let_and_return)]
-#![allow(clippy::redundant_closure_call)]
-#![allow(clippy::no_effect)]
-#![allow(clippy::unnecessary_operation)]
-#![allow(clippy::never_loop)]
-#![allow(clippy::needless_if)]
 #![warn(clippy::excessive_nesting)]
-#![allow(clippy::collapsible_if, clippy::blocks_in_conditions)]
+#![allow(
+    unused,
+    clippy::let_and_return,
+    clippy::redundant_closure_call,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::never_loop,
+    clippy::needless_if,
+    clippy::collapsible_if,
+    clippy::blocks_in_conditions,
+    clippy::single_match,
+)]
 
 #[macro_use]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr
index dafcd442055..ccdaecdd481 100644
--- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr
+++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr
@@ -1,5 +1,5 @@
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:21:25
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:25:25
    |
 LL |                 let w = { 3 };
    |                         ^^^^^
@@ -9,7 +9,7 @@ LL |                 let w = { 3 };
    = help: to override `-D warnings` add `#[allow(clippy::excessive_nesting)]`
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:67:17
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:71:17
    |
 LL | /                 impl C {
 LL | |                     pub fn c() {}
@@ -19,7 +19,7 @@ LL | |                 }
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:81:25
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:85:25
    |
 LL |                 let x = { 1 }; // not a warning, but cc is
    |                         ^^^^^
@@ -27,7 +27,7 @@ LL |                 let x = { 1 }; // not a warning, but cc is
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:98:17
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:102:17
    |
 LL | /                 pub mod e {
 LL | |                     pub mod f {}
@@ -37,7 +37,7 @@ LL | |                 } // not here
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:111:18
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:115:18
    |
 LL |     a_but_not({{{{{{{{0}}}}}}}});
    |                  ^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |     a_but_not({{{{{{{{0}}}}}}}});
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:112:12
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:116:12
    |
 LL |     a.a({{{{{{{{{0}}}}}}}}});
    |            ^^^^^^^^^^^^^
@@ -53,7 +53,7 @@ LL |     a.a({{{{{{{{{0}}}}}}}}});
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:113:12
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:117:12
    |
 LL |     (0, {{{{{{{1}}}}}}});
    |            ^^^^^^^^^
@@ -61,7 +61,7 @@ LL |     (0, {{{{{{{1}}}}}}});
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:118:25
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:122:25
    |
 LL |                   if true {
    |  _________________________^
@@ -74,7 +74,7 @@ LL | |                 }
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:130:29
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:134:29
    |
 LL |                   let z = (|| {
    |  _____________________________^
@@ -86,7 +86,7 @@ LL | |                 })();
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:149:13
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:153:13
    |
 LL |     y += {{{{{5}}}}};
    |             ^^^^^
@@ -94,7 +94,7 @@ LL |     y += {{{{{5}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:150:20
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:154:20
    |
 LL |     let z = y + {{{{{{{{{5}}}}}}}}};
    |                    ^^^^^^^^^^^^^
@@ -102,7 +102,7 @@ LL |     let z = y + {{{{{{{{{5}}}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:151:12
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:155:12
    |
 LL |     [0, {{{{{{{{{{0}}}}}}}}}}];
    |            ^^^^^^^^^^^^^^^
@@ -110,7 +110,7 @@ LL |     [0, {{{{{{{{{{0}}}}}}}}}}];
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:152:25
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:25
    |
 LL |     let mut xx = [0; {{{{{{{{100}}}}}}}}];
    |                         ^^^^^^^^^^^^^
@@ -118,7 +118,7 @@ LL |     let mut xx = [0; {{{{{{{{100}}}}}}}}];
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:153:11
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:157:11
    |
 LL |     xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -126,7 +126,7 @@ LL |     xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:154:13
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:13
    |
 LL |     &mut {{{{{{{{{{y}}}}}}}}}};
    |             ^^^^^^^^^^^^^^^
@@ -134,7 +134,7 @@ LL |     &mut {{{{{{{{{{y}}}}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:17
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:17
    |
 LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
    |                 ^^^^
@@ -142,7 +142,7 @@ LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:28
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:28
    |
 LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
    |                            ^^^^^^^^^^
@@ -150,7 +150,7 @@ LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:28
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:28
    |
 LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
    |                            ^^^^^^^^^^^^^
@@ -158,7 +158,7 @@ LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:48
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:48
    |
 LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
    |                                                ^^^^^^^^
@@ -166,7 +166,7 @@ LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:14
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:14
    |
 LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
    |              ^^^^^^^^^^^^^^
@@ -174,7 +174,7 @@ LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:35
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:35
    |
 LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
    |                                   ^^^^^^^^^^^^
@@ -182,7 +182,7 @@ LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:23
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:166:23
    |
 LL |     let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -190,7 +190,7 @@ LL |     let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:8
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:8
    |
 LL |     {{{{1;}}}}..{{{{{{3}}}}}};
    |        ^^^^
@@ -198,7 +198,7 @@ LL |     {{{{1;}}}}..{{{{{{3}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:20
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:20
    |
 LL |     {{{{1;}}}}..{{{{{{3}}}}}};
    |                    ^^^^^^^
@@ -206,7 +206,7 @@ LL |     {{{{1;}}}}..{{{{{{3}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:165:8
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:169:8
    |
 LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
    |        ^^^^
@@ -214,7 +214,7 @@ LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:165:21
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:169:21
    |
 LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -222,7 +222,7 @@ LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:166:10
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:170:10
    |
 LL |     ..{{{{{{{5}}}}}}};
    |          ^^^^^^^^^
@@ -230,7 +230,7 @@ LL |     ..{{{{{{{5}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:167:11
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:171:11
    |
 LL |     ..={{{{{3}}}}};
    |           ^^^^^
@@ -238,7 +238,7 @@ LL |     ..={{{{{3}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:8
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:172:8
    |
 LL |     {{{{{1;}}}}}..;
    |        ^^^^^^
@@ -246,7 +246,7 @@ LL |     {{{{{1;}}}}}..;
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:170:20
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:174:20
    |
 LL |     loop { break {{{{1}}}} };
    |                    ^^^^^
@@ -254,7 +254,7 @@ LL |     loop { break {{{{1}}}} };
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:171:13
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:13
    |
 LL |     loop {{{{{{}}}}}}
    |             ^^^^^^
@@ -262,7 +262,7 @@ LL |     loop {{{{{{}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:173:14
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:177:14
    |
 LL |     match {{{{{{true}}}}}} {
    |              ^^^^^^^^^^
@@ -270,7 +270,7 @@ LL |     match {{{{{{true}}}}}} {
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:174:20
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:178:20
    |
 LL |         true => {{{{}}}},
    |                    ^^
@@ -278,7 +278,7 @@ LL |         true => {{{{}}}},
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:21
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:179:21
    |
 LL |         false => {{{{}}}},
    |                     ^^
@@ -286,7 +286,7 @@ LL |         false => {{{{}}}},
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:181:17
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:185:17
    |
 LL | /                 {
 LL | |                     println!("warning! :)");
@@ -296,7 +296,7 @@ LL | |                 }
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:190:28
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:194:28
    |
 LL |     async fn c() -> u32 {{{{{{{0}}}}}}}
    |                            ^^^^^^^^^
@@ -304,7 +304,7 @@ LL |     async fn c() -> u32 {{{{{{{0}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:196:8
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:200:8
    |
 LL |     {{{{b().await}}}};
    |        ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 41d5afd3efe..320578bfabc 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -1,11 +1,15 @@
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:38:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::get-unwrap` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::get_unwrap)]`
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &boxed_slice[1];
+   |                 ~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:38:17
@@ -18,11 +22,16 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:39:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_slice[0];
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:39:17
@@ -33,11 +42,16 @@ LL |         let _ = some_slice.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:40:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vec[0];
+   |                 ~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:40:17
@@ -48,11 +62,16 @@ LL |         let _ = some_vec.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a VecDeque
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vecdeque[0];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17
@@ -63,11 +82,16 @@ LL |         let _ = some_vecdeque.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a HashMap
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:42:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_hashmap[&1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:42:17
@@ -78,11 +102,16 @@ LL |         let _ = some_hashmap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a BTreeMap
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:43:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_btreemap[&1];
+   |                 ~~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:43:17
@@ -93,11 +122,16 @@ LL |         let _ = some_btreemap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _: u8 = boxed_slice[1];
+   |                     ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:22
@@ -108,11 +142,16 @@ LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:52:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         boxed_slice[0] = 1;
+   |         ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:52:10
@@ -123,11 +162,16 @@ LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_slice[0] = 1;
+   |         ~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:10
@@ -138,11 +182,16 @@ LL |         *some_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:54:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vec[0] = 1;
+   |         ~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:54:10
@@ -153,11 +202,16 @@ LL |         *some_vec.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a VecDeque
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:55:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vecdeque[0] = 1;
+   |         ~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:55:10
@@ -168,11 +222,16 @@ LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:67:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:67:17
@@ -183,11 +242,16 @@ LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:68:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:68:17
@@ -198,17 +262,27 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:75:13
    |
 LL |     let _ = boxed_slice.get(1).unwrap();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |     let _ = &boxed_slice[1];
+   |             ~~~~~~~~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:93:17
    |
 LL |         let _ = Box::new([0]).get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&Box::new([0])[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &Box::new([0])[1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed
index 60f6a385fc5..b376d55a402 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.fixed
+++ b/src/tools/clippy/tests/ui/assigning_clones.fixed
@@ -3,6 +3,7 @@
 #![allow(clippy::ptr_arg)] // https://github.com/rust-lang/rust-clippy/issues/10612
 #![allow(clippy::needless_late_init)]
 #![allow(clippy::box_collection)]
+#![allow(clippy::boxed_local)]
 #![warn(clippy::assigning_clones)]
 
 use std::borrow::ToOwned;
@@ -182,6 +183,31 @@ impl Clone for AvoidRecursiveCloneFrom {
     }
 }
 
+// Deref handling
+fn clone_into_deref_method(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
+    (*a).clone_from(&b);
+}
+
+fn clone_into_deref_with_clone_method(mut a: DerefWrapperWithClone<HasCloneFrom>, b: HasCloneFrom) {
+    (*a).clone_from(&b);
+}
+
+fn clone_into_box_method(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
+    (*a).clone_from(&b);
+}
+
+fn clone_into_self_deref_method(a: &mut DerefWrapperWithClone<HasCloneFrom>, b: DerefWrapperWithClone<HasCloneFrom>) {
+    a.clone_from(&b);
+}
+
+fn clone_into_deref_function(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
+    Clone::clone_from(&mut *a, &b);
+}
+
+fn clone_into_box_function(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
+    Clone::clone_from(&mut *a, &b);
+}
+
 // ToOwned
 fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
     ref_str.clone_into(mut_string);
@@ -328,3 +354,45 @@ mod borrowck_conflicts {
         path = path.components().as_path().to_owned();
     }
 }
+
+struct DerefWrapper<T>(T);
+
+impl<T> Deref for DerefWrapper<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for DerefWrapper<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+struct DerefWrapperWithClone<T>(T);
+
+impl<T> Deref for DerefWrapperWithClone<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for DerefWrapperWithClone<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T: Clone> Clone for DerefWrapperWithClone<T> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+
+    fn clone_from(&mut self, source: &Self) {
+        *self = Self(source.0.clone());
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs
index 6eb85be511a..11a5d4459c3 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.rs
+++ b/src/tools/clippy/tests/ui/assigning_clones.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::ptr_arg)] // https://github.com/rust-lang/rust-clippy/issues/10612
 #![allow(clippy::needless_late_init)]
 #![allow(clippy::box_collection)]
+#![allow(clippy::boxed_local)]
 #![warn(clippy::assigning_clones)]
 
 use std::borrow::ToOwned;
@@ -182,6 +183,31 @@ impl Clone for AvoidRecursiveCloneFrom {
     }
 }
 
+// Deref handling
+fn clone_into_deref_method(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
+    *a = b.clone();
+}
+
+fn clone_into_deref_with_clone_method(mut a: DerefWrapperWithClone<HasCloneFrom>, b: HasCloneFrom) {
+    *a = b.clone();
+}
+
+fn clone_into_box_method(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
+    *a = b.clone();
+}
+
+fn clone_into_self_deref_method(a: &mut DerefWrapperWithClone<HasCloneFrom>, b: DerefWrapperWithClone<HasCloneFrom>) {
+    *a = b.clone();
+}
+
+fn clone_into_deref_function(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
+    *a = Clone::clone(&b);
+}
+
+fn clone_into_box_function(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
+    *a = Clone::clone(&b);
+}
+
 // ToOwned
 fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
     *mut_string = ref_str.to_owned();
@@ -328,3 +354,45 @@ mod borrowck_conflicts {
         path = path.components().as_path().to_owned();
     }
 }
+
+struct DerefWrapper<T>(T);
+
+impl<T> Deref for DerefWrapper<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for DerefWrapper<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+struct DerefWrapperWithClone<T>(T);
+
+impl<T> Deref for DerefWrapperWithClone<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for DerefWrapperWithClone<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T: Clone> Clone for DerefWrapperWithClone<T> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+
+    fn clone_from(&mut self, source: &Self) {
+        *self = Self(source.0.clone());
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr
index a68516376ab..19724a6d4ec 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.stderr
+++ b/src/tools/clippy/tests/ui/assigning_clones.stderr
@@ -1,5 +1,5 @@
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:24:5
+  --> tests/ui/assigning_clones.rs:25:5
    |
 LL |     *mut_thing = value_thing.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(&value_thing)`
@@ -8,142 +8,178 @@ LL |     *mut_thing = value_thing.clone();
    = help: to override `-D warnings` add `#[allow(clippy::assigning_clones)]`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:28:5
+  --> tests/ui/assigning_clones.rs:29:5
    |
 LL |     *mut_thing = ref_thing.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:32:5
+  --> tests/ui/assigning_clones.rs:33:5
    |
 LL |     mut_thing = ref_thing.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:36:5
+  --> tests/ui/assigning_clones.rs:37:5
    |
 LL |     *mut_thing = Clone::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:40:5
+  --> tests/ui/assigning_clones.rs:41:5
    |
 LL |     mut_thing = Clone::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:44:5
+  --> tests/ui/assigning_clones.rs:45:5
    |
 LL |     *mut_thing = Clone::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:48:5
+  --> tests/ui/assigning_clones.rs:49:5
    |
 LL |     *mut_thing = HasCloneFrom::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:52:5
+  --> tests/ui/assigning_clones.rs:53:5
    |
 LL |     *mut_thing = <HasCloneFrom as Clone>::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:57:5
+  --> tests/ui/assigning_clones.rs:58:5
    |
 LL |     *(mut_thing + &mut HasCloneFrom) = ref_thing.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `(mut_thing + &mut HasCloneFrom).clone_from(ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:62:5
+  --> tests/ui/assigning_clones.rs:63:5
    |
 LL |     *mut_thing = (ref_thing + ref_thing).clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing + ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:67:5
+  --> tests/ui/assigning_clones.rs:68:5
    |
 LL |     s = format!("{} {}", "hello", "world").clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `s.clone_from(&format!("{} {}", "hello", "world"))`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:72:5
+  --> tests/ui/assigning_clones.rs:73:5
    |
 LL |     s = Clone::clone(&format!("{} {}", "hello", "world"));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut s, &format!("{} {}", "hello", "world"))`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:78:9
+  --> tests/ui/assigning_clones.rs:79:9
    |
 LL |         a = b.clone();
    |         ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:149:5
+  --> tests/ui/assigning_clones.rs:150:5
    |
 LL |     a = b.clone();
    |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:156:5
+  --> tests/ui/assigning_clones.rs:157:5
    |
 LL |     a = b.clone();
    |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:157:5
+  --> tests/ui/assigning_clones.rs:158:5
    |
 LL |     a = c.to_owned();
    |     ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)`
 
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:188:5
+   |
+LL |     *a = b.clone();
+   |     ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:192:5
+   |
+LL |     *a = b.clone();
+   |     ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:196:5
+   |
+LL |     *a = b.clone();
+   |     ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:200:5
+   |
+LL |     *a = b.clone();
+   |     ^^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:204:5
+   |
+LL |     *a = Clone::clone(&b);
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut *a, &b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:208:5
+   |
+LL |     *a = Clone::clone(&b);
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut *a, &b)`
+
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:187:5
+  --> tests/ui/assigning_clones.rs:213:5
    |
 LL |     *mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:191:5
+  --> tests/ui/assigning_clones.rs:217:5
    |
 LL |     mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:212:5
+  --> tests/ui/assigning_clones.rs:238:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:216:5
+  --> tests/ui/assigning_clones.rs:242:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:220:5
+  --> tests/ui/assigning_clones.rs:246:5
    |
 LL |     *mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:224:5
+  --> tests/ui/assigning_clones.rs:250:5
    |
 LL |     mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:229:5
+  --> tests/ui/assigning_clones.rs:255:5
    |
 LL |     s = format!("{} {}", "hello", "world").to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `format!("{} {}", "hello", "world").clone_into(&mut s)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:234:5
+  --> tests/ui/assigning_clones.rs:260:5
    |
 LL |     s = ToOwned::to_owned(&format!("{} {}", "hello", "world"));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s)`
 
-error: aborting due to 24 previous errors
+error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
index b15857c325a..2adaecc96d6 100644
--- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
+++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
@@ -9,7 +9,7 @@ note: the lint level is defined here
    |
 LL | #![deny(clippy::bind_instead_of_map)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: try
+help: use `map` instead
    |
 LL |     let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
    |                        ~~~                       ~          ~~~~~~~
@@ -20,7 +20,7 @@ error: using `Result.and_then(|x| Ok(y))`, which is more succinctly expressed as
 LL |     let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: try
+help: use `map` instead
    |
 LL |     let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
    |                               ~~~                       ~          ~~~~~~~
@@ -31,7 +31,7 @@ error: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as
 LL |     let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: try
+help: use `map_err` instead
    |
 LL |     let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } else { s.len() });
    |                                ~~~~~~~                       ~~~~~~~~~~~~          ~~~~~~~
@@ -48,7 +48,7 @@ LL | |         }
 LL | |     });
    | |______^
    |
-help: try
+help: use `map` instead
    |
 LL ~     Some("42").map(|s| {
 LL |         if {
@@ -82,7 +82,7 @@ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed
 LL |     let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: try
+help: use `map` instead
    |
 LL |     let _ = Some("").map(|s| if s.len() == 20 { m!() } else { Some(20) });
    |                      ~~~                        ~~~~          ~~~~~~~~
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr
index 01627ff5b94..4b4618ee1bb 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr
@@ -9,14 +9,13 @@ note: the lint level is defined here
    |
 LL | #![deny(clippy::implicit_hasher)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
-help: consider adding a type parameter
+help: add a type parameter for `BuildHasher`
    |
-LL | pub fn ice_3717<S: ::std::hash::BuildHasher + Default>(_: &HashSet<usize, S>) {
-   |                +++++++++++++++++++++++++++++++++++++++     ~~~~~~~~~~~~~~~~~
-help: ...and use generic constructor
+LL ~ pub fn ice_3717<S: ::std::hash::BuildHasher + Default>(_: &HashSet<usize, S>) {
+LL |
+LL |     let _ = [0u8; 0];
+LL ~     let _: HashSet<usize> = HashSet::default();
    |
-LL |     let _: HashSet<usize> = HashSet::default();
-   |                             ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.rs b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
index 8af60890390..aaca32ab2d9 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6254.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
@@ -2,7 +2,8 @@
 // panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())',
 // compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5
 
-#[allow(clippy::derive_partial_eq_without_eq)]
+#![allow(clippy::derive_partial_eq_without_eq, clippy::single_match)]
+
 #[derive(PartialEq)]
 struct Foo(i32);
 const FOO_REF_REF: &&Foo = &&Foo(42);
diff --git a/src/tools/clippy/tests/ui/create_dir.stderr b/src/tools/clippy/tests/ui/create_dir.stderr
index 9c6e640ca78..ab51705bb55 100644
--- a/src/tools/clippy/tests/ui/create_dir.stderr
+++ b/src/tools/clippy/tests/ui/create_dir.stderr
@@ -2,16 +2,25 @@ error: calling `std::fs::create_dir` where there may be a better way
   --> tests/ui/create_dir.rs:10:5
    |
 LL |     std::fs::create_dir("foo");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::create-dir` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::create_dir)]`
+help: consider calling `std::fs::create_dir_all` instead
+   |
+LL |     create_dir_all("foo");
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: calling `std::fs::create_dir` where there may be a better way
   --> tests/ui/create_dir.rs:11:5
    |
 LL |     std::fs::create_dir("bar").unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("bar")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider calling `std::fs::create_dir_all` instead
+   |
+LL |     create_dir_all("bar").unwrap();
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
index 7d3c3f7c918..b3d74b9ff61 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
@@ -81,7 +81,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/dbg_macro.rs:48:5
    |
 LL |     dbg!();
-   |     ^^^^^^^
+   |     ^^^^^^
    |
 help: remove the invocation before committing it to a version control system
    |
@@ -136,7 +136,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/dbg_macro.rs:43:13
    |
 LL |             dbg!();
-   |             ^^^^^^^
+   |             ^^^^^^
 ...
 LL |     expand_to_dbg!();
    |     ---------------- in this macro invocation
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
index 16e51f4742e..b8e91906b93 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
@@ -2,7 +2,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/auxiliary/submodule.rs:2:5
    |
 LL |     dbg!();
-   |     ^^^^^^^
+   |     ^^^^^^
    |
    = note: `-D clippy::dbg-macro` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]`
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index d3c34fb3716..5617db90a47 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -2,23 +2,18 @@
 // Use that command to update this file and do not edit by hand.
 // Manual edits will be overwritten.
 
-#![warn(clippy::should_assert_eq)]
-#![warn(clippy::extend_from_slice)]
-#![warn(clippy::range_step_by_zero)]
-#![warn(clippy::unstable_as_slice)]
-#![warn(clippy::unstable_as_mut_slice)]
-#![warn(clippy::misaligned_transmute)]
-#![warn(clippy::assign_ops)]
-#![warn(clippy::if_let_redundant_pattern_matching)]
-#![warn(clippy::unsafe_vector_initialization)]
-#![warn(clippy::unused_collect)]
-#![warn(clippy::replace_consts)]
-#![warn(clippy::regex_macro)]
-#![warn(clippy::find_map)]
-#![warn(clippy::filter_map)]
-#![warn(clippy::pub_enum_variant_names)]
-#![warn(clippy::wrong_pub_self_convention)]
-#![warn(clippy::maybe_misused_cfg)]
-#![warn(clippy::mismatched_target_os)]
+#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq`
+#![warn(clippy::extend_from_slice)] //~ ERROR: lint `clippy::extend_from_slice`
+#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero`
+#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice`
+#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice`
+#![warn(clippy::misaligned_transmute)] //~ ERROR: lint `clippy::misaligned_transmute`
+#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops`
+#![warn(clippy::unsafe_vector_initialization)] //~ ERROR: lint `clippy::unsafe_vector_initialization`
+#![warn(clippy::unused_collect)] //~ ERROR: lint `clippy::unused_collect`
+#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts`
+#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro`
+#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names`
+#![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index 49b90c70c06..b3e1646c804 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -1,4 +1,4 @@
-error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
+error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can
   --> tests/ui/deprecated.rs:5:9
    |
 LL | #![warn(clippy::should_assert_eq)]
@@ -7,107 +7,77 @@ LL | #![warn(clippy::should_assert_eq)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
-error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
+error: lint `clippy::extend_from_slice` has been removed: `Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization
   --> tests/ui/deprecated.rs:6:9
    |
 LL | #![warn(clippy::extend_from_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
+error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator
   --> tests/ui/deprecated.rs:7:9
    |
 LL | #![warn(clippy::range_step_by_zero)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable
   --> tests/ui/deprecated.rs:8:9
    |
 LL | #![warn(clippy::unstable_as_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
+error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable
   --> tests/ui/deprecated.rs:9:9
    |
 LL | #![warn(clippy::unstable_as_mut_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
+error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`
   --> tests/ui/deprecated.rs:10:9
    |
 LL | #![warn(clippy::misaligned_transmute)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
+error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy
   --> tests/ui/deprecated.rs:11:9
    |
 LL | #![warn(clippy::assign_ops)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
+error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower
   --> tests/ui/deprecated.rs:12:9
    |
-LL | #![warn(clippy::if_let_redundant_pattern_matching)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
-  --> tests/ui/deprecated.rs:13:9
-   |
 LL | #![warn(clippy::unsafe_vector_initialization)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
-  --> tests/ui/deprecated.rs:14:9
+error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]`
+  --> tests/ui/deprecated.rs:13:9
    |
 LL | #![warn(clippy::unused_collect)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
-  --> tests/ui/deprecated.rs:15:9
+error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated
+  --> tests/ui/deprecated.rs:14:9
    |
 LL | #![warn(clippy::replace_consts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
-  --> tests/ui/deprecated.rs:16:9
+error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018
+  --> tests/ui/deprecated.rs:15:9
    |
 LL | #![warn(clippy::regex_macro)]
    |         ^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
-  --> tests/ui/deprecated.rs:17:9
-   |
-LL | #![warn(clippy::find_map)]
-   |         ^^^^^^^^^^^^^^^^
-
-error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
-  --> tests/ui/deprecated.rs:18:9
-   |
-LL | #![warn(clippy::filter_map)]
-   |         ^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
-  --> tests/ui/deprecated.rs:19:9
+error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config
+  --> tests/ui/deprecated.rs:16:9
    |
 LL | #![warn(clippy::pub_enum_variant_names)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
-  --> tests/ui/deprecated.rs:20:9
+error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config
+  --> tests/ui/deprecated.rs:17:9
    |
 LL | #![warn(clippy::wrong_pub_self_convention)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::maybe_misused_cfg` has been removed: this lint has been replaced by `unexpected_cfgs`
-  --> tests/ui/deprecated.rs:21:9
-   |
-LL | #![warn(clippy::maybe_misused_cfg)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::mismatched_target_os` has been removed: this lint has been replaced by `unexpected_cfgs`
-  --> tests/ui/deprecated.rs:22:9
-   |
-LL | #![warn(clippy::mismatched_target_os)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 18 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/deprecated_old.rs b/src/tools/clippy/tests/ui/deprecated_old.rs
deleted file mode 100644
index 356ad5f060b..00000000000
--- a/src/tools/clippy/tests/ui/deprecated_old.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#[warn(unstable_as_slice)]
-//~^ ERROR: lint `unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized
-//~| NOTE: `-D renamed-and-removed-lints` implied by `-D warnings`
-#[warn(unstable_as_mut_slice)]
-//~^ ERROR: lint `unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been st
-#[warn(misaligned_transmute)]
-//~^ ERROR: lint `misaligned_transmute` has been removed: this lint has been split into ca
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated_old.stderr b/src/tools/clippy/tests/ui/deprecated_old.stderr
deleted file mode 100644
index 685bca64df5..00000000000
--- a/src/tools/clippy/tests/ui/deprecated_old.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: lint `unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
-  --> tests/ui/deprecated_old.rs:1:8
-   |
-LL | #[warn(unstable_as_slice)]
-   |        ^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
-
-error: lint `unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
-  --> tests/ui/deprecated_old.rs:4:8
-   |
-LL | #[warn(unstable_as_mut_slice)]
-   |        ^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
-  --> tests/ui/deprecated_old.rs:6:8
-   |
-LL | #[warn(misaligned_transmute)]
-   |        ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.fixed b/src/tools/clippy/tests/ui/deref_by_slicing.fixed
index a3c2e845666..87b33b1f881 100644
--- a/src/tools/clippy/tests/ui/deref_by_slicing.fixed
+++ b/src/tools/clippy/tests/ui/deref_by_slicing.fixed
@@ -25,4 +25,8 @@ fn main() {
 
     let bytes: &[u8] = &[];
     let _ = (&*bytes).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice
+
+    // issue 12751
+    let a = &mut [1, 2, 3][..];
+    let _ = &*a;
 }
diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.rs b/src/tools/clippy/tests/ui/deref_by_slicing.rs
index 5b4a73712ee..8d8882a1781 100644
--- a/src/tools/clippy/tests/ui/deref_by_slicing.rs
+++ b/src/tools/clippy/tests/ui/deref_by_slicing.rs
@@ -25,4 +25,8 @@ fn main() {
 
     let bytes: &[u8] = &[];
     let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice
+
+    // issue 12751
+    let a = &mut [1, 2, 3][..];
+    let _ = &a[..];
 }
diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.stderr b/src/tools/clippy/tests/ui/deref_by_slicing.stderr
index 17b00610899..ceb9ab6db73 100644
--- a/src/tools/clippy/tests/ui/deref_by_slicing.stderr
+++ b/src/tools/clippy/tests/ui/deref_by_slicing.stderr
@@ -55,5 +55,11 @@ error: slicing when dereferencing would work
 LL |     let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice
    |             ^^^^^^^^^^^^ help: reborrow the original value instead: `(&*bytes)`
 
-error: aborting due to 9 previous errors
+error: slicing when dereferencing would work
+  --> tests/ui/deref_by_slicing.rs:31:13
+   |
+LL |     let _ = &a[..];
+   |             ^^^^^^ help: reborrow the original value instead: `&*a`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs b/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs
new file mode 100644
index 00000000000..a18b4c3ac53
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs
@@ -0,0 +1,10 @@
+// This is a regression test for <https://github.com/rust-lang/rust-clippy/issues/13183>.
+// It should not warn on missing backticks on footnote references.
+
+#![warn(clippy::doc_markdown)]
+// Should not warn!
+//! Here's a footnote[^example_footnote_identifier]
+//!
+//! [^example_footnote_identifier]: This is merely an example.
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_drop.stderr b/src/tools/clippy/tests/ui/empty_drop.stderr
index 4223ddaf3fb..d4d020fec30 100644
--- a/src/tools/clippy/tests/ui/empty_drop.stderr
+++ b/src/tools/clippy/tests/ui/empty_drop.stderr
@@ -4,10 +4,11 @@ error: empty drop implementation
 LL | / impl Drop for Foo {
 LL | |     fn drop(&mut self) {}
 LL | | }
-   | |_^ help: try removing this impl
+   | |_^
    |
    = note: `-D clippy::empty-drop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_drop)]`
+   = help: try removing this impl
 
 error: empty drop implementation
   --> tests/ui/empty_drop.rs:23:1
@@ -17,7 +18,9 @@ LL | |     fn drop(&mut self) {
 LL | |         {}
 LL | |     }
 LL | | }
-   | |_^ help: try removing this impl
+   | |_^
+   |
+   = help: try removing this impl
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 7126f279945..ca422ee29c1 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -2,6 +2,7 @@
 #![allow(unused)]
 #![allow(
     clippy::needless_borrow,
+    clippy::needless_option_as_deref,
     clippy::needless_pass_by_value,
     clippy::no_effect,
     clippy::option_map_unit_fn,
@@ -482,3 +483,19 @@ mod issue_12853 {
         x();
     }
 }
+
+mod issue_13073 {
+    fn get_default() -> Option<&'static str> {
+        Some("foo")
+    }
+
+    pub fn foo() {
+        // shouldn't lint
+        let bind: Option<String> = None;
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
+        let bind: Option<&'static str> = None;
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
+        // should lint
+        let _field = bind.or_else(get_default).unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 0787abf5f3e..c0db91c03ef 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -2,6 +2,7 @@
 #![allow(unused)]
 #![allow(
     clippy::needless_borrow,
+    clippy::needless_option_as_deref,
     clippy::needless_pass_by_value,
     clippy::no_effect,
     clippy::option_map_unit_fn,
@@ -482,3 +483,19 @@ mod issue_12853 {
         x();
     }
 }
+
+mod issue_13073 {
+    fn get_default() -> Option<&'static str> {
+        Some("foo")
+    }
+
+    pub fn foo() {
+        // shouldn't lint
+        let bind: Option<String> = None;
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
+        let bind: Option<&'static str> = None;
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
+        // should lint
+        let _field = bind.or_else(|| get_default()).unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index c757601042f..5540261fc57 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -1,5 +1,5 @@
 error: redundant closure
-  --> tests/ui/eta.rs:29:27
+  --> tests/ui/eta.rs:30:27
    |
 LL |     let a = Some(1u8).map(|a| foo(a));
    |                           ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
@@ -8,31 +8,31 @@ LL |     let a = Some(1u8).map(|a| foo(a));
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:33:40
+  --> tests/ui/eta.rs:34:40
    |
 LL |     let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
    |                                        ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
 
 error: redundant closure
-  --> tests/ui/eta.rs:34:35
+  --> tests/ui/eta.rs:35:35
    |
 LL |     let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
    |                                   ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:35:26
+  --> tests/ui/eta.rs:36:26
    |
 LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
    |                          ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
 
 error: redundant closure
-  --> tests/ui/eta.rs:42:27
+  --> tests/ui/eta.rs:43:27
    |
 LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> tests/ui/eta.rs:94:51
+  --> tests/ui/eta.rs:95:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -41,166 +41,172 @@ LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:95:51
+  --> tests/ui/eta.rs:96:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
    |                                                   ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
 
 error: redundant closure
-  --> tests/ui/eta.rs:97:42
+  --> tests/ui/eta.rs:98:42
    |
 LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
    |                                          ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
 
 error: redundant closure
-  --> tests/ui/eta.rs:101:29
+  --> tests/ui/eta.rs:102:29
    |
 LL |     let e = Some("str").map(|s| s.to_string());
    |                             ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
 
 error: redundant closure
-  --> tests/ui/eta.rs:102:27
+  --> tests/ui/eta.rs:103:27
    |
 LL |     let e = Some('a').map(|s| s.to_uppercase());
    |                           ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:104:65
+  --> tests/ui/eta.rs:105:65
    |
 LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:167:22
+  --> tests/ui/eta.rs:168:22
    |
 LL |     requires_fn_once(|| x());
    |                      ^^^^^^ help: replace the closure with the function itself: `x`
 
 error: redundant closure
-  --> tests/ui/eta.rs:174:27
+  --> tests/ui/eta.rs:175:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> tests/ui/eta.rs:179:27
+  --> tests/ui/eta.rs:180:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:211:28
+  --> tests/ui/eta.rs:212:28
    |
 LL |     x.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:212:28
+  --> tests/ui/eta.rs:213:28
    |
 LL |     y.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:213:28
+  --> tests/ui/eta.rs:214:28
    |
 LL |     z.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:220:21
+  --> tests/ui/eta.rs:221:21
    |
 LL |         Some(1).map(|n| closure(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:224:21
+  --> tests/ui/eta.rs:225:21
    |
 LL |         Some(1).map(|n| in_loop(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
 
 error: redundant closure
-  --> tests/ui/eta.rs:317:18
+  --> tests/ui/eta.rs:318:18
    |
 LL |     takes_fn_mut(|| f());
    |                  ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:320:19
+  --> tests/ui/eta.rs:321:19
    |
 LL |     takes_fn_once(|| f());
    |                   ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:324:26
+  --> tests/ui/eta.rs:325:26
    |
 LL |     move || takes_fn_mut(|| f_used_once())
    |                          ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
 
 error: redundant closure
-  --> tests/ui/eta.rs:336:19
+  --> tests/ui/eta.rs:337:19
    |
 LL |     array_opt.map(|a| a.as_slice());
    |                   ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
 
 error: redundant closure
-  --> tests/ui/eta.rs:339:19
+  --> tests/ui/eta.rs:340:19
    |
 LL |     slice_opt.map(|s| s.len());
    |                   ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
 
 error: redundant closure
-  --> tests/ui/eta.rs:342:17
+  --> tests/ui/eta.rs:343:17
    |
 LL |     ptr_opt.map(|p| p.is_null());
    |                 ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
 
 error: redundant closure
-  --> tests/ui/eta.rs:346:17
+  --> tests/ui/eta.rs:347:17
    |
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
 error: redundant closure
-  --> tests/ui/eta.rs:406:19
+  --> tests/ui/eta.rs:407:19
    |
 LL |     let _ = f(&0, |x, y| f2(x, y));
    |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:434:22
+  --> tests/ui/eta.rs:435:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:438:22
+  --> tests/ui/eta.rs:439:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:451:18
+  --> tests/ui/eta.rs:452:18
    |
 LL |         test.map(|t| t.method())
    |                  ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:458:30
+  --> tests/ui/eta.rs:459:30
    |
 LL |                     test.map(|t| t.method())
    |                              ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:477:38
+  --> tests/ui/eta.rs:478:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `&f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:481:38
+  --> tests/ui/eta.rs:482:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `f`
 
-error: aborting due to 33 previous errors
+error: redundant closure
+  --> tests/ui/eta.rs:499:35
+   |
+LL |         let _field = bind.or_else(|| get_default()).unwrap();
+   |                                   ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
+
+error: aborting due to 34 previous errors
 
diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr
index 6d8e166a649..81e4fb6765d 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.stderr
+++ b/src/tools/clippy/tests/ui/excessive_precision.stderr
@@ -2,100 +2,179 @@ error: float has excessive precision
   --> tests/ui/excessive_precision.rs:20:26
    |
 LL |     const BAD32_1: f32 = 0.123_456_789_f32;
-   |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79_f32`
+   |                          ^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::excessive-precision` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::excessive_precision)]`
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD32_1: f32 = 0.123_456_79_f32;
+   |                          ~~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:21:26
    |
 LL |     const BAD32_2: f32 = 0.123_456_789;
-   |                          ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
+   |                          ^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD32_2: f32 = 0.123_456_79;
+   |                          ~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:22:26
    |
 LL |     const BAD32_3: f32 = 0.100_000_000_000_1;
-   |                          ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
+   |                          ^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD32_3: f32 = 0.1;
+   |                          ~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:23:29
    |
 LL |     const BAD32_EDGE: f32 = 1.000_000_9;
-   |                             ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001`
+   |                             ^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD32_EDGE: f32 = 1.000_001;
+   |                             ~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:27:26
    |
 LL |     const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD64_3: f64 = 0.1;
+   |                          ~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:30:22
    |
 LL |     println!("{:?}", 8.888_888_888_888_888_888_888);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     println!("{:?}", 8.888_888_888_888_89);
+   |                      ~~~~~~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:41:22
    |
 LL |     let bad32: f32 = 1.123_456_789;
-   |                      ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8`
+   |                      ^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad32: f32 = 1.123_456_8;
+   |                      ~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:42:26
    |
 LL |     let bad32_suf: f32 = 1.123_456_789_f32;
-   |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
+   |                          ^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad32_suf: f32 = 1.123_456_8_f32;
+   |                          ~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:43:21
    |
 LL |     let bad32_inf = 1.123_456_789_f32;
-   |                     ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
+   |                     ^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad32_inf = 1.123_456_8_f32;
+   |                     ~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:53:36
    |
 LL |     let bad_vec32: Vec<f32> = vec![0.123_456_789];
-   |                                    ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
+   |                                    ^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad_vec32: Vec<f32> = vec![0.123_456_79];
+   |                                    ~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:54:36
    |
 LL |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78`
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_78];
+   |                                    ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:58:24
    |
 LL |     let bad_e32: f32 = 1.123_456_788_888e-10;
-   |                        ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10`
+   |                        ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad_e32: f32 = 1.123_456_8e-10;
+   |                        ~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:61:27
    |
 LL |     let bad_bige32: f32 = 1.123_456_788_888E-10;
-   |                           ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10`
+   |                           ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad_bige32: f32 = 1.123_456_8E-10;
+   |                           ~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:70:13
    |
 LL |     let _ = 2.225_073_858_507_201_1e-308_f64;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `2.225_073_858_507_201e-308_f64`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let _ = 2.225_073_858_507_201e-308_f64;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:73:13
    |
 LL |     let _ = 1.000_000_000_000_001e-324_f64;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0_f64`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let _ = 0_f64;
+   |             ~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:83:20
    |
 LL |     const _: f64 = 3.0000000000000000e+00;
-   |                    ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `3.0`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const _: f64 = 3.0;
+   |                    ~~~
 
 error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index c25e79a3617..28b477b6921 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -278,3 +278,16 @@ mod issue_10058 {
         }
     }
 }
+
+mod issue_13123 {
+    pub fn test() {
+        let mut vec = vec![1, 2, 3, 4];
+        let mut _index = 0;
+        'label: for v in vec {
+            _index += 1;
+            if v == 1 {
+                break 'label;
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
index e28f8783f9c..1b2d1f8570a 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
@@ -57,5 +57,11 @@ LL |         for _item in slice {
    |
    = note: `idx_u32` is of type `u32`, making it ineligible for `Iterator::enumerate`
 
-error: aborting due to 9 previous errors
+error: the variable `_index` is used as a loop counter
+  --> tests/ui/explicit_counter_loop.rs:286:9
+   |
+LL |         'label: for v in vec {
+   |         ^^^^^^^^^^^^^^^^^^^^ help: consider using: `'label: for (_index, v) in vec.into_iter().enumerate()`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr
index e5bb8d13269..a05b7138bc9 100644
--- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr
@@ -2,106 +2,190 @@ error: casting function pointer `foo` to `i8`
   --> tests/ui/fn_to_numeric_cast_any.rs:23:13
    |
 LL |     let _ = foo as i8;
-   |             ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i8`
+   |             ^^^^^^^^^
    |
    = note: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_any)]`
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i8;
+   |             ~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i16`
   --> tests/ui/fn_to_numeric_cast_any.rs:26:13
    |
 LL |     let _ = foo as i16;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i16`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i16;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i32`
   --> tests/ui/fn_to_numeric_cast_any.rs:28:13
    |
 LL |     let _ = foo as i32;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i32`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i32;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i64`
   --> tests/ui/fn_to_numeric_cast_any.rs:30:13
    |
 LL |     let _ = foo as i64;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i64`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i64;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i128`
   --> tests/ui/fn_to_numeric_cast_any.rs:32:13
    |
 LL |     let _ = foo as i128;
-   |             ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i128`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i128;
+   |             ~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `isize`
   --> tests/ui/fn_to_numeric_cast_any.rs:34:13
    |
 LL |     let _ = foo as isize;
-   |             ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as isize`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as isize;
+   |             ~~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u8`
   --> tests/ui/fn_to_numeric_cast_any.rs:37:13
    |
 LL |     let _ = foo as u8;
-   |             ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u8`
+   |             ^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u8;
+   |             ~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u16`
   --> tests/ui/fn_to_numeric_cast_any.rs:39:13
    |
 LL |     let _ = foo as u16;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u16`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u16;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u32`
   --> tests/ui/fn_to_numeric_cast_any.rs:41:13
    |
 LL |     let _ = foo as u32;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u32`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u32;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u64`
   --> tests/ui/fn_to_numeric_cast_any.rs:43:13
    |
 LL |     let _ = foo as u64;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u64`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u64;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u128`
   --> tests/ui/fn_to_numeric_cast_any.rs:45:13
    |
 LL |     let _ = foo as u128;
-   |             ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u128`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u128;
+   |             ~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:47:13
    |
 LL |     let _ = foo as usize;
-   |             ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as usize`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as usize;
+   |             ~~~~~~~~~~~~~~
 
 error: casting function pointer `Struct::static_method` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:52:13
    |
 LL |     let _ = Struct::static_method as usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `Struct::static_method() as usize`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = Struct::static_method() as usize;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting function pointer `f` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:57:5
    |
 LL |     f as usize
-   |     ^^^^^^^^^^ help: did you mean to invoke the function?: `f() as usize`
+   |     ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     f() as usize
+   |
 
 error: casting function pointer `T::static_method` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:62:5
    |
 LL |     T::static_method as usize
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `T::static_method() as usize`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     T::static_method() as usize
+   |
 
 error: casting function pointer `(clos as fn(u32) -> u32)` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:69:13
    |
 LL |     let _ = (clos as fn(u32) -> u32) as usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `(clos as fn(u32) -> u32)() as usize`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = (clos as fn(u32) -> u32)() as usize;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `*const ()`
   --> tests/ui/fn_to_numeric_cast_any.rs:74:13
    |
 LL |     let _ = foo as *const ();
-   |             ^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as *const ()`
+   |             ^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as *const ();
+   |             ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/for_kv_map.fixed b/src/tools/clippy/tests/ui/for_kv_map.fixed
index a2112d7b730..1733b29128f 100644
--- a/src/tools/clippy/tests/ui/for_kv_map.fixed
+++ b/src/tools/clippy/tests/ui/for_kv_map.fixed
@@ -40,6 +40,16 @@ fn main() {
         let _k = k;
     }
 
+    let m: HashMap<u64, u64> = HashMap::new();
+    let rm = &m;
+    'label: for k in rm.keys() {
+        //~^ ERROR: you seem to want to iterate on a map's keys
+        let _k = k;
+        if *k == 0u64 {
+            break 'label;
+        }
+    }
+
     // The following should not produce warnings.
 
     let m: HashMap<u64, u64> = HashMap::new();
diff --git a/src/tools/clippy/tests/ui/for_kv_map.rs b/src/tools/clippy/tests/ui/for_kv_map.rs
index 1b7959b8f92..de465a7c8e6 100644
--- a/src/tools/clippy/tests/ui/for_kv_map.rs
+++ b/src/tools/clippy/tests/ui/for_kv_map.rs
@@ -40,6 +40,16 @@ fn main() {
         let _k = k;
     }
 
+    let m: HashMap<u64, u64> = HashMap::new();
+    let rm = &m;
+    'label: for (k, _value) in rm {
+        //~^ ERROR: you seem to want to iterate on a map's keys
+        let _k = k;
+        if *k == 0u64 {
+            break 'label;
+        }
+    }
+
     // The following should not produce warnings.
 
     let m: HashMap<u64, u64> = HashMap::new();
diff --git a/src/tools/clippy/tests/ui/for_kv_map.stderr b/src/tools/clippy/tests/ui/for_kv_map.stderr
index f4ce473d095..adcc3ab8fdb 100644
--- a/src/tools/clippy/tests/ui/for_kv_map.stderr
+++ b/src/tools/clippy/tests/ui/for_kv_map.stderr
@@ -55,5 +55,16 @@ help: use the corresponding method
 LL |     for k in rm.keys() {
    |         ~    ~~~~~~~~~
 
-error: aborting due to 5 previous errors
+error: you seem to want to iterate on a map's keys
+  --> tests/ui/for_kv_map.rs:45:32
+   |
+LL |     'label: for (k, _value) in rm {
+   |                                ^^
+   |
+help: use the corresponding method
+   |
+LL |     'label: for k in rm.keys() {
+   |                 ~    ~~~~~~~~~
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
index a08b6657dcc..0f8b279da1e 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -1,14 +1,18 @@
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:37:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> tests/ui/get_unwrap.rs:9:9
    |
 LL | #![deny(clippy::get_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &boxed_slice[1];
+   |                 ~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:37:17
@@ -21,11 +25,16 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:38:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_slice[0];
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:38:17
@@ -36,11 +45,16 @@ LL |         let _ = some_slice.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:39:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vec[0];
+   |                 ~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:39:17
@@ -51,11 +65,16 @@ LL |         let _ = some_vec.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a VecDeque
   --> tests/ui/get_unwrap.rs:40:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vecdeque[0];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:40:17
@@ -66,11 +85,16 @@ LL |         let _ = some_vecdeque.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a HashMap
   --> tests/ui/get_unwrap.rs:41:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_hashmap[&1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:41:17
@@ -81,11 +105,16 @@ LL |         let _ = some_hashmap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a BTreeMap
   --> tests/ui/get_unwrap.rs:42:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_btreemap[&1];
+   |                 ~~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:42:17
@@ -96,11 +125,16 @@ LL |         let _ = some_btreemap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:46:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _: u8 = boxed_slice[1];
+   |                     ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:46:22
@@ -111,11 +145,16 @@ LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:51:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         boxed_slice[0] = 1;
+   |         ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:51:10
@@ -126,11 +165,16 @@ LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:52:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_slice[0] = 1;
+   |         ~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:52:10
@@ -141,11 +185,16 @@ LL |         *some_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:53:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vec[0] = 1;
+   |         ~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:53:10
@@ -156,11 +205,16 @@ LL |         *some_vec.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a VecDeque
   --> tests/ui/get_unwrap.rs:54:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vecdeque[0] = 1;
+   |         ~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:54:10
@@ -171,11 +225,16 @@ LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:66:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:66:17
@@ -186,11 +245,16 @@ LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:67:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:67:17
@@ -201,29 +265,49 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:77:24
    |
 LL |         let _x: &i32 = f.get(1 + 2).unwrap();
-   |                        ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]`
+   |                        ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x: &i32 = &f[1 + 2];
+   |                        ~~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:80:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().to_string();
-   |                  ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x = f[1 + 2].to_string();
+   |                  ~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:83:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().abs();
-   |                  ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x = f[1 + 2].abs();
+   |                  ~~~~~~~~
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:100:33
    |
 LL |                         let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |                         let b = &mut rest[linidx(j, k) - linidx(i, k) - 1];
+   |                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/if_let_mutex.rs b/src/tools/clippy/tests/ui/if_let_mutex.rs
index cb6915e0eba..bb0eadfca1c 100644
--- a/src/tools/clippy/tests/ui/if_let_mutex.rs
+++ b/src/tools/clippy/tests/ui/if_let_mutex.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::if_let_mutex)]
+#![allow(clippy::redundant_pattern_matching)]
 
 use std::ops::Deref;
 use std::sync::Mutex;
@@ -50,4 +51,12 @@ fn mutex_ref(mutex: &Mutex<i32>) {
     };
 }
 
+fn multiple_mutexes(m1: &Mutex<()>, m2: &Mutex<()>) {
+    if let Ok(_) = m1.lock() {
+        m2.lock();
+    } else {
+        m1.lock();
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_let_mutex.stderr b/src/tools/clippy/tests/ui/if_let_mutex.stderr
index 6e0115c23af..45df4ac4d67 100644
--- a/src/tools/clippy/tests/ui/if_let_mutex.stderr
+++ b/src/tools/clippy/tests/ui/if_let_mutex.stderr
@@ -1,5 +1,5 @@
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
-  --> tests/ui/if_let_mutex.rs:10:5
+  --> tests/ui/if_let_mutex.rs:11:5
    |
 LL |       if let Err(locked) = m.lock() {
    |       ^                    - this Mutex will remain locked for the entire `if let`-block...
@@ -19,7 +19,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::if_let_mutex)]`
 
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
-  --> tests/ui/if_let_mutex.rs:23:5
+  --> tests/ui/if_let_mutex.rs:24:5
    |
 LL |       if let Some(locked) = m.lock().unwrap().deref() {
    |       ^                     - this Mutex will remain locked for the entire `if let`-block...
@@ -37,7 +37,7 @@ LL | |     };
    = help: move the lock call outside of the `if let ...` expression
 
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
-  --> tests/ui/if_let_mutex.rs:45:5
+  --> tests/ui/if_let_mutex.rs:46:5
    |
 LL |       if let Ok(i) = mutex.lock() {
    |       ^              ----- this Mutex will remain locked for the entire `if let`-block...
@@ -53,5 +53,21 @@ LL | |     };
    |
    = help: move the lock call outside of the `if let ...` expression
 
-error: aborting due to 3 previous errors
+error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
+  --> tests/ui/if_let_mutex.rs:55:5
+   |
+LL |       if let Ok(_) = m1.lock() {
+   |       ^              -- this Mutex will remain locked for the entire `if let`-block...
+   |  _____|
+   | |
+LL | |         m2.lock();
+LL | |     } else {
+LL | |         m1.lock();
+   | |         -- ... and is tried to lock again here, which will always deadlock.
+LL | |     }
+   | |_____^
+   |
+   = help: move the lock call outside of the `if let ...` expression
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
new file mode 100644
index 00000000000..ad13372a68b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
@@ -0,0 +1,119 @@
+#![warn(clippy::if_then_some_else_none)]
+#![allow(clippy::redundant_pattern_matching, clippy::unnecessary_lazy_evaluations)]
+
+fn main() {
+    // Should issue an error.
+    let _ = foo().then(||  { println!("true!"); "foo" });
+
+    // Should issue an error when macros are used.
+    let _ = matches!(true, true).then(||  { println!("true!"); matches!(true, false) });
+
+    // Should issue an error. Binary expression `o < 32` should be parenthesized.
+    let x = Some(5);
+    let _ = x.and_then(|o| (o < 32).then_some(o));
+    //~^ ERROR: this could be simplified with `bool::then_some`
+
+    // Should issue an error. Unary expression `!x` should be parenthesized.
+    let x = true;
+    let _ = (!x).then_some(0);
+    //~^ ERROR: this could be simplified with `bool::then_some`
+
+    // Should not issue an error since the `else` block has a statement besides `None`.
+    let _ = if foo() {
+        println!("true!");
+        Some("foo")
+    } else {
+        eprintln!("false...");
+        None
+    };
+
+    // Should not issue an error since there are more than 2 blocks in the if-else chain.
+    let _ = if foo() {
+        println!("foo true!");
+        Some("foo")
+    } else if bar() {
+        println!("bar true!");
+        Some("bar")
+    } else {
+        None
+    };
+
+    let _ = if foo() {
+        println!("foo true!");
+        Some("foo")
+    } else {
+        bar().then(|| {
+            println!("bar true!");
+            "bar"
+        })
+    };
+
+    // Should not issue an error since the `then` block has `None`, not `Some`.
+    let _ = if foo() { None } else { Some("foo is false") };
+
+    // Should not issue an error since the `else` block doesn't use `None` directly.
+    let _ = if foo() { Some("foo is true") } else { into_none() };
+
+    // Should not issue an error since the `then` block doesn't use `Some` directly.
+    let _ = if foo() { into_some("foo") } else { None };
+}
+
+#[clippy::msrv = "1.49"]
+fn _msrv_1_49() {
+    // `bool::then` was stabilized in 1.50. Do not lint this
+    let _ = if foo() {
+        println!("true!");
+        Some(149)
+    } else {
+        None
+    };
+}
+
+#[clippy::msrv = "1.50"]
+fn _msrv_1_50() {
+    let _ = foo().then(||  { println!("true!"); 150 });
+}
+
+fn foo() -> bool {
+    unimplemented!()
+}
+
+fn bar() -> bool {
+    unimplemented!()
+}
+
+fn into_some<T>(v: T) -> Option<T> {
+    Some(v)
+}
+
+fn into_none<T>() -> Option<T> {
+    None
+}
+
+// Should not warn
+fn f(b: bool, v: Option<()>) -> Option<()> {
+    if b {
+        v?; // This is a potential early return, is not equivalent with `bool::then`
+
+        Some(())
+    } else {
+        None
+    }
+}
+
+fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> {
+    let x = if b {
+        #[allow(clippy::let_unit_value)]
+        let _ = v?;
+        Some(())
+    } else {
+        None
+    };
+
+    Ok(())
+}
+
+const fn issue12103(x: u32) -> Option<u32> {
+    // Should not issue an error in `const` context
+    if x > 42 { Some(150) } else { None }
+}
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
index ccde154bd56..73edbb7da2a 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::if_then_some_else_none)]
-#![allow(clippy::redundant_pattern_matching)]
+#![allow(clippy::redundant_pattern_matching, clippy::unnecessary_lazy_evaluations)]
 
 fn main() {
     // Should issue an error.
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
index e0a95aebdc1..aed01e026cb 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
@@ -9,9 +9,8 @@ LL | |         Some("foo")
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
+   | |_____^ help: try: `foo().then(||  { println!("true!"); "foo" })`
    |
-   = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ "foo" })`
    = note: `-D clippy::if-then-some-else-none` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]`
 
@@ -26,25 +25,19 @@ LL | |         Some(matches!(true, false))
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
-   |
-   = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
+   | |_____^ help: try: `matches!(true, true).then(||  { println!("true!"); matches!(true, false) })`
 
 error: this could be simplified with `bool::then_some`
   --> tests/ui/if_then_some_else_none.rs:25:28
    |
 LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(o < 32).then_some(o)`
 
 error: this could be simplified with `bool::then_some`
   --> tests/ui/if_then_some_else_none.rs:30:13
    |
 LL |     let _ = if !x { Some(0) } else { None };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider using `bool::then_some` like: `(!x).then_some(0)`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(!x).then_some(0)`
 
 error: this could be simplified with `bool::then`
   --> tests/ui/if_then_some_else_none.rs:86:13
@@ -57,9 +50,7 @@ LL | |         Some(150)
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
-   |
-   = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ 150 })`
+   | |_____^ help: try: `foo().then(||  { println!("true!"); 150 })`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/implicit_hasher.fixed b/src/tools/clippy/tests/ui/implicit_hasher.fixed
new file mode 100644
index 00000000000..2d6dc0274cf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_hasher.fixed
@@ -0,0 +1,102 @@
+//@aux-build:proc_macros.rs
+#![deny(clippy::implicit_hasher)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::cmp::Eq;
+use std::collections::{HashMap, HashSet};
+use std::hash::{BuildHasher, Hash};
+
+pub trait Foo<T>: Sized {
+    fn make() -> (Self, Self);
+}
+
+impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
+    fn make() -> (Self, Self) {
+        // OK, don't suggest to modify these
+        let _: HashMap<i32, i32> = HashMap::new();
+        let _: HashSet<i32> = HashSet::new();
+
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+    }
+}
+impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
+    fn make() -> (Self, Self) {
+        ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
+    }
+}
+impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
+    fn make() -> (Self, Self) {
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+    }
+}
+
+impl<K: Hash + Eq, V, S: BuildHasher + Default> Foo<i32> for HashMap<K, V, S> {
+    fn make() -> (Self, Self) {
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
+    }
+}
+impl<S: BuildHasher + Default> Foo<i64> for HashMap<String, String, S> {
+    fn make() -> (Self, Self) {
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
+    }
+}
+
+impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
+    }
+}
+impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
+    }
+}
+
+impl<T: Hash + Eq, S: BuildHasher + Default> Foo<i32> for HashSet<T, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
+    }
+}
+impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
+    }
+}
+
+pub fn map<S: ::std::hash::BuildHasher>(map: &mut HashMap<i32, i32, S>) {}
+
+pub fn set<S: ::std::hash::BuildHasher>(set: &mut HashSet<i32, S>) {}
+
+#[inline_macros]
+pub mod gen {
+    use super::*;
+    inline! {
+        impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
+            fn make() -> (Self, Self) {
+                (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+            }
+        }
+
+        pub fn bar(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+    }
+}
+
+// When the macro is in a different file, the suggestion spans can't be combined properly
+// and should not cause an ICE
+// See #2707
+#[macro_use]
+#[path = "auxiliary/test_macro.rs"]
+pub mod test_macro;
+__implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A);
+
+// #4260
+external! {
+    pub fn f(input: &HashMap<u32, u32>) {}
+}
+
+// #7712
+pub async fn election_vote<S: ::std::hash::BuildHasher>(_data: HashMap<i32, i32, S>) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs
index f7cd541741b..0a334357bd1 100644
--- a/src/tools/clippy/tests/ui/implicit_hasher.rs
+++ b/src/tools/clippy/tests/ui/implicit_hasher.rs
@@ -1,11 +1,8 @@
 //@aux-build:proc_macros.rs
-//@no-rustfix
 #![deny(clippy::implicit_hasher)]
-#![allow(unused)]
 
 #[macro_use]
 extern crate proc_macros;
-use proc_macros::external;
 
 use std::cmp::Eq;
 use std::collections::{HashMap, HashSet};
@@ -68,9 +65,11 @@ impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> {
     }
 }
 
-pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+pub fn map(map: &mut HashMap<i32, i32>) {}
 
-#[proc_macros::inline_macros]
+pub fn set(set: &mut HashSet<i32>) {}
+
+#[inline_macros]
 pub mod gen {
     use super::*;
     inline! {
diff --git a/src/tools/clippy/tests/ui/implicit_hasher.stderr b/src/tools/clippy/tests/ui/implicit_hasher.stderr
index a3df8edf389..48c6ebc209c 100644
--- a/src/tools/clippy/tests/ui/implicit_hasher.stderr
+++ b/src/tools/clippy/tests/ui/implicit_hasher.stderr
@@ -1,40 +1,121 @@
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:14:1
+error: impl for `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:15:35
+   |
+LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
+   |                                   ^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> tests/ui/implicit_hasher.rs:2:9
+   |
+LL | #![deny(clippy::implicit_hasher)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
+LL |     fn make() -> (Self, Self) {
+...
+LL |
+LL ~         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+   |
+
+error: impl for `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:24:36
+   |
+LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
+   |                                    ^^^^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
+LL |     fn make() -> (Self, Self) {
+LL ~         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
+   |
+
+error: impl for `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:29:19
+   |
+LL | impl Foo<i16> for HashMap<String, String> {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
+LL |     fn make() -> (Self, Self) {
+LL ~         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+   |
+
+error: impl for `HashSet` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:46:32
+   |
+LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
+   |                                ^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
+LL |     fn make() -> (Self, Self) {
+LL ~         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
    |
-LL | pub trait Foo<T>: Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:71:1
+error: impl for `HashSet` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:51:19
+   |
+LL | impl Foo<i16> for HashSet<String> {
+   |                   ^^^^^^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
+LL |     fn make() -> (Self, Self) {
+LL ~         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
    |
-LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:74:1
+error: parameter of type `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:68:22
+   |
+LL | pub fn map(map: &mut HashMap<i32, i32>) {}
+   |                      ^^^^^^^^^^^^^^^^^
    |
-LL | pub mod gen {
-   | ^^^^^^^^^^^
+help: add a type parameter for `BuildHasher`
+   |
+LL | pub fn map<S: ::std::hash::BuildHasher>(map: &mut HashMap<i32, i32, S>) {}
+   |           +++++++++++++++++++++++++++++           ~~~~~~~~~~~~~~~~~~~~
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:92:1
+error: parameter of type `HashSet` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:70:22
+   |
+LL | pub fn set(set: &mut HashSet<i32>) {}
+   |                      ^^^^^^^^^^^^
    |
-LL | pub mod test_macro;
-   | ^^^^^^^^^^^^^^^^^^^
+help: add a type parameter for `BuildHasher`
+   |
+LL | pub fn set<S: ::std::hash::BuildHasher>(set: &mut HashSet<i32, S>) {}
+   |           +++++++++++++++++++++++++++++           ~~~~~~~~~~~~~~~
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:96:1
+error: impl for `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:76:43
+   |
+LL |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
+   |                                           ^^^^^^^^^^^^^
    |
-LL | external! {
-   | ^^^^^^^^^
+   = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add a type parameter for `BuildHasher`
+   |
+LL ~         impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
+LL |             fn make() -> (Self, Self) {
+LL ~                 (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
    |
-   = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:101:1
+error: parameter of type `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:100:35
    |
 LL | pub async fn election_vote(_data: HashMap<i32, i32>) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   ^^^^^^^^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL | pub async fn election_vote<S: ::std::hash::BuildHasher>(_data: HashMap<i32, i32, S>) {}
+   |                           +++++++++++++++++++++++++++++        ~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 6 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr
index f06d4e983c5..3b06f26f5a0 100644
--- a/src/tools/clippy/tests/ui/implicit_return.stderr
+++ b/src/tools/clippy/tests/ui/implicit_return.stderr
@@ -2,88 +2,157 @@ error: missing `return` statement
   --> tests/ui/implicit_return.rs:15:5
    |
 LL |     true
-   |     ^^^^ help: add `return` as shown: `return true`
+   |     ^^^^
    |
    = note: `-D clippy::implicit-return` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::implicit_return)]`
+help: add `return` as shown
+   |
+LL |     return true
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:19:15
    |
 LL |     if true { true } else { false }
-   |               ^^^^ help: add `return` as shown: `return true`
+   |               ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     if true { return true } else { false }
+   |               ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:19:29
    |
 LL |     if true { true } else { false }
-   |                             ^^^^^ help: add `return` as shown: `return false`
+   |                             ^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     if true { true } else { return false }
+   |                             ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:25:17
    |
 LL |         true => false,
-   |                 ^^^^^ help: add `return` as shown: `return false`
+   |                 ^^^^^
+   |
+help: add `return` as shown
+   |
+LL |         true => return false,
+   |                 ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:26:20
    |
 LL |         false => { true },
-   |                    ^^^^ help: add `return` as shown: `return true`
+   |                    ^^^^
+   |
+help: add `return` as shown
+   |
+LL |         false => { return true },
+   |                    ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:39:9
    |
 LL |         break true;
-   |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |         ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |         return true;
+   |         ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:46:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:54:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:72:18
    |
 LL |     let _ = || { true };
-   |                  ^^^^ help: add `return` as shown: `return true`
+   |                  ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     let _ = || { return true };
+   |                  ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:73:16
    |
 LL |     let _ = || true;
-   |                ^^^^ help: add `return` as shown: `return true`
+   |                ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     let _ = || return true;
+   |                ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:81:5
    |
 LL |     format!("test {}", "test")
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return format!("test {}", "test")
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:90:5
    |
 LL |     m!(true, false)
-   |     ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
+   |     ^^^^^^^^^^^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return m!(true, false)
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:96:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:101:17
    |
 LL |                 break 'outer false;
-   |                 ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
+   |                 ^^^^^^^^^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |                 return false;
+   |                 ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:116:5
@@ -104,7 +173,12 @@ error: missing `return` statement
   --> tests/ui/implicit_return.rs:130:5
    |
 LL |     true
-   |     ^^^^ help: add `return` as shown: `return true`
+   |     ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return true
+   |
 
 error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.stderr b/src/tools/clippy/tests/ui/lossy_float_literal.stderr
index b5a07418734..3026854e317 100644
--- a/src/tools/clippy/tests/ui/lossy_float_literal.stderr
+++ b/src/tools/clippy/tests/ui/lossy_float_literal.stderr
@@ -2,70 +2,124 @@ error: literal cannot be represented as the underlying type without loss of prec
   --> tests/ui/lossy_float_literal.rs:14:18
    |
 LL |     let _: f32 = 16_777_217.0;
-   |                  ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0`
+   |                  ^^^^^^^^^^^^
    |
    = note: `-D clippy::lossy-float-literal` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::lossy_float_literal)]`
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = 16_777_216.0;
+   |                  ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:15:18
    |
 LL |     let _: f32 = 16_777_219.0;
-   |                  ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
+   |                  ^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = 16_777_220.0;
+   |                  ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:16:18
    |
 LL |     let _: f32 = 16_777_219.;
-   |                  ^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
+   |                  ^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = 16_777_220.0;
+   |                  ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:17:18
    |
 LL |     let _: f32 = 16_777_219.000;
-   |                  ^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
+   |                  ^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = 16_777_220.0;
+   |                  ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:18:13
    |
 LL |     let _ = 16_777_219f32;
-   |             ^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220_f32`
+   |             ^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _ = 16_777_220_f32;
+   |             ~~~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:19:19
    |
 LL |     let _: f32 = -16_777_219.0;
-   |                   ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
+   |                   ^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = -16_777_220.0;
+   |                   ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:21:18
    |
 LL |     let _: f64 = 9_007_199_254_740_993.0;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f64 = 9_007_199_254_740_992.0;
+   |                  ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:22:18
    |
 LL |     let _: f64 = 9_007_199_254_740_993.;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f64 = 9_007_199_254_740_992.0;
+   |                  ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:23:18
    |
 LL |     let _: f64 = 9_007_199_254_740_993.00;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f64 = 9_007_199_254_740_992.0;
+   |                  ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:24:13
    |
 LL |     let _ = 9_007_199_254_740_993f64;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992_f64`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _ = 9_007_199_254_740_992_f64;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> tests/ui/lossy_float_literal.rs:25:19
    |
 LL |     let _: f64 = -9_007_199_254_740_993.0;
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f64 = -9_007_199_254_740_992.0;
+   |                   ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.rs b/src/tools/clippy/tests/ui/missing_trait_methods.rs
index 1b09b717ff7..55b904bde59 100644
--- a/src/tools/clippy/tests/ui/missing_trait_methods.rs
+++ b/src/tools/clippy/tests/ui/missing_trait_methods.rs
@@ -49,4 +49,12 @@ impl B for Complete {
     }
 }
 
+trait MissingMultiple {
+    fn one() {}
+    fn two() {}
+    fn three() {}
+}
+
+impl MissingMultiple for Partial {}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.stderr b/src/tools/clippy/tests/ui/missing_trait_methods.stderr
index f5d5d4418b2..9c4968b022d 100644
--- a/src/tools/clippy/tests/ui/missing_trait_methods.stderr
+++ b/src/tools/clippy/tests/ui/missing_trait_methods.stderr
@@ -24,5 +24,41 @@ help: implement the method
 LL |     fn b<'a, T: AsRef<[u8]>>(a: &'a T) -> &'a [u8] {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: missing trait method provided by default: `one`
+  --> tests/ui/missing_trait_methods.rs:58:1
+   |
+LL | impl MissingMultiple for Partial {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: implement the method
+  --> tests/ui/missing_trait_methods.rs:53:5
+   |
+LL |     fn one() {}
+   |     ^^^^^^^^
+
+error: missing trait method provided by default: `two`
+  --> tests/ui/missing_trait_methods.rs:58:1
+   |
+LL | impl MissingMultiple for Partial {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: implement the method
+  --> tests/ui/missing_trait_methods.rs:54:5
+   |
+LL |     fn two() {}
+   |     ^^^^^^^^
+
+error: missing trait method provided by default: `three`
+  --> tests/ui/missing_trait_methods.rs:58:1
+   |
+LL | impl MissingMultiple for Partial {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: implement the method
+  --> tests/ui/missing_trait_methods.rs:55:5
+   |
+LL |     fn three() {}
+   |     ^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
index 5478372cbe0..c1dc8b5e8d0 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
@@ -333,4 +333,12 @@ fn main() {
         f(&y); // Don't lint
         f("".to_owned()); // Lint
     }
+    {
+        fn takes_writer<T: std::io::Write>(_: T) {}
+
+        fn issue_12856(mut buffer: &mut Vec<u8>) {
+            takes_writer(&mut buffer); // Don't lint, would make buffer unavailable later
+            buffer.extend(b"\n");
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
index 2643815d939..c7f66824d58 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
@@ -333,4 +333,12 @@ fn main() {
         f(&y); // Don't lint
         f(&"".to_owned()); // Lint
     }
+    {
+        fn takes_writer<T: std::io::Write>(_: T) {}
+
+        fn issue_12856(mut buffer: &mut Vec<u8>) {
+            takes_writer(&mut buffer); // Don't lint, would make buffer unavailable later
+            buffer.extend(b"\n");
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/needless_pub_self.stderr b/src/tools/clippy/tests/ui/needless_pub_self.stderr
index 0bff2e4b8b7..1fdd8416565 100644
--- a/src/tools/clippy/tests/ui/needless_pub_self.stderr
+++ b/src/tools/clippy/tests/ui/needless_pub_self.stderr
@@ -2,22 +2,27 @@ error: unnecessary `pub(self)`
   --> tests/ui/needless_pub_self.rs:13:1
    |
 LL | pub(self) fn a() {}
-   | ^^^^^^^^^ help: remove it
+   | ^^^^^^^^^
    |
    = note: `-D clippy::needless-pub-self` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_pub_self)]`
+   = help: remove it
 
 error: unnecessary `pub(in self)`
   --> tests/ui/needless_pub_self.rs:14:1
    |
 LL | pub(in self) fn b() {}
-   | ^^^^^^^^^^^^ help: remove it
+   | ^^^^^^^^^^^^
+   |
+   = help: remove it
 
 error: unnecessary `pub(self)`
   --> tests/ui/needless_pub_self.rs:20:5
    |
 LL |     pub(self) fn f() {}
-   |     ^^^^^^^^^ help: remove it
+   |     ^^^^^^^^^
+   |
+   = help: remove it
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index d117e8bf9c7..52b0155a762 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -177,3 +177,9 @@ fn issue_12371(x: usize) -> bool {
     // Should not warn!
     !x != 0
 }
+
+// Not linted because it is slow to do so
+// https://github.com/rust-lang/rust-clippy/issues/13206
+fn many_ops(a: bool, b: bool, c: bool, d: bool, e: bool, f: bool) -> bool {
+    (a && c && f) || (!a && b && !d) || (!b && !c && !e) || (d && e && !f)
+}
diff --git a/src/tools/clippy/tests/ui/patterns.fixed b/src/tools/clippy/tests/ui/patterns.fixed
index 332cba97155..feaec33ac15 100644
--- a/src/tools/clippy/tests/ui/patterns.fixed
+++ b/src/tools/clippy/tests/ui/patterns.fixed
@@ -1,7 +1,7 @@
 //@aux-build:proc_macros.rs
 #![warn(clippy::all)]
 #![allow(unused)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::single_match)]
 
 #[macro_use]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/patterns.rs b/src/tools/clippy/tests/ui/patterns.rs
index 45d907688e3..53812c7deec 100644
--- a/src/tools/clippy/tests/ui/patterns.rs
+++ b/src/tools/clippy/tests/ui/patterns.rs
@@ -1,7 +1,7 @@
 //@aux-build:proc_macros.rs
 #![warn(clippy::all)]
 #![allow(unused)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::single_match)]
 
 #[macro_use]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index d70c9f8d06c..b810fd8224f 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -13,7 +13,10 @@
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
+#![allow(clippy::manual_find_map)]
+#![allow(clippy::manual_filter_map)]
 #![allow(clippy::useless_conversion)]
+#![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::non_canonical_clone_impl)]
 #![allow(clippy::non_canonical_partial_ord_impl)]
@@ -47,6 +50,7 @@
 #![allow(invalid_value)]
 #![allow(invalid_from_utf8_unchecked)]
 #![allow(let_underscore_drop)]
+#![allow(unexpected_cfgs)]
 #![allow(enum_intrinsics_non_enums)]
 #![allow(non_fmt_panics)]
 #![allow(named_arguments_used_positionally)]
@@ -55,65 +59,72 @@
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![warn(clippy::almost_complete_range)]
-#![warn(clippy::disallowed_names)]
-#![warn(clippy::blocks_in_conditions)]
-#![warn(clippy::blocks_in_conditions)]
-#![warn(clippy::blocks_in_conditions)]
-#![warn(clippy::box_collection)]
-#![warn(clippy::redundant_static_lifetimes)]
-#![warn(clippy::cognitive_complexity)]
-#![warn(clippy::derived_hash_with_manual_eq)]
-#![warn(clippy::disallowed_methods)]
-#![warn(clippy::disallowed_types)]
-#![warn(clippy::mixed_read_write_in_expression)]
-#![warn(clippy::useless_conversion)]
-#![warn(clippy::match_result_ok)]
-#![warn(clippy::non_canonical_clone_impl)]
-#![warn(clippy::non_canonical_partial_ord_impl)]
-#![warn(clippy::arithmetic_side_effects)]
-#![warn(clippy::overly_complex_bool_expr)]
-#![warn(clippy::new_without_default)]
-#![warn(clippy::bind_instead_of_map)]
-#![warn(clippy::expect_used)]
-#![warn(clippy::map_unwrap_or)]
-#![warn(clippy::map_unwrap_or)]
-#![warn(clippy::unwrap_used)]
-#![warn(clippy::panicking_overflow_checks)]
-#![warn(clippy::needless_borrow)]
-#![warn(clippy::expect_used)]
-#![warn(clippy::map_unwrap_or)]
-#![warn(clippy::unwrap_used)]
-#![warn(clippy::single_char_add_str)]
-#![warn(clippy::module_name_repetitions)]
-#![warn(clippy::missing_const_for_thread_local)]
-#![warn(clippy::recursive_format_impl)]
-#![warn(clippy::unwrap_or_default)]
-#![warn(clippy::invisible_characters)]
-#![warn(invalid_reference_casting)]
-#![warn(suspicious_double_ref_op)]
-#![warn(invalid_nan_comparisons)]
-#![warn(drop_bounds)]
-#![warn(dropping_copy_types)]
-#![warn(dropping_references)]
-#![warn(useless_ptr_null_checks)]
-#![warn(for_loops_over_fallibles)]
-#![warn(for_loops_over_fallibles)]
-#![warn(for_loops_over_fallibles)]
-#![warn(forgetting_copy_types)]
-#![warn(forgetting_references)]
-#![warn(array_into_iter)]
-#![warn(invalid_atomic_ordering)]
-#![warn(invalid_value)]
-#![warn(invalid_from_utf8_unchecked)]
-#![warn(let_underscore_drop)]
-#![warn(enum_intrinsics_non_enums)]
-#![warn(non_fmt_panics)]
-#![warn(named_arguments_used_positionally)]
-#![warn(temporary_cstring_as_ptr)]
-#![warn(undropped_manually_drops)]
-#![warn(unknown_lints)]
-#![warn(unused_labels)]
-#![warn(ambiguous_wide_pointer_comparisons)]
+#![allow(clippy::reversed_empty_ranges)]
+#![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
+#![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
+#![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
+#![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_stmt`
+#![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions`
+#![warn(clippy::box_collection)] //~ ERROR: lint `clippy::box_vec`
+#![warn(clippy::redundant_static_lifetimes)] //~ ERROR: lint `clippy::const_static_lifetime`
+#![warn(clippy::cognitive_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity`
+#![warn(clippy::derived_hash_with_manual_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq`
+#![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method`
+#![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type`
+#![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence`
+#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
+#![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion`
+#![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
+#![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result`
+#![warn(clippy::non_canonical_clone_impl)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type`
+#![warn(clippy::non_canonical_partial_ord_impl)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type`
+#![warn(clippy::arithmetic_side_effects)] //~ ERROR: lint `clippy::integer_arithmetic`
+#![warn(clippy::overly_complex_bool_expr)] //~ ERROR: lint `clippy::logic_bug`
+#![warn(clippy::new_without_default)] //~ ERROR: lint `clippy::new_without_default_derive`
+#![warn(clippy::bind_instead_of_map)] //~ ERROR: lint `clippy::option_and_then_some`
+#![warn(clippy::expect_used)] //~ ERROR: lint `clippy::option_expect_used`
+#![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or`
+#![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or_else`
+#![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used`
+#![warn(clippy::panicking_overflow_checks)] //~ ERROR: lint `clippy::overflow_check_conditional`
+#![warn(clippy::needless_borrow)] //~ ERROR: lint `clippy::ref_in_deref`
+#![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used`
+#![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
+#![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str`
+#![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter`
+#![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
+#![warn(clippy::recursive_format_impl)] //~ ERROR: lint `clippy::to_string_in_display`
+#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
+#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space`
+#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
+#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
+#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
+#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
+#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
+#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
+#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
+#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy`
+#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref`
+#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array`
+#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
+#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref`
+#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
+#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
+#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg`
+#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
+#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
+#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
+#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
+#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
+#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
+#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
+#![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
+#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 8d0ac3c8f95..e03df1658ee 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -13,7 +13,10 @@
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
+#![allow(clippy::manual_find_map)]
+#![allow(clippy::manual_filter_map)]
 #![allow(clippy::useless_conversion)]
+#![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::non_canonical_clone_impl)]
 #![allow(clippy::non_canonical_partial_ord_impl)]
@@ -47,6 +50,7 @@
 #![allow(invalid_value)]
 #![allow(invalid_from_utf8_unchecked)]
 #![allow(let_underscore_drop)]
+#![allow(unexpected_cfgs)]
 #![allow(enum_intrinsics_non_enums)]
 #![allow(non_fmt_panics)]
 #![allow(named_arguments_used_positionally)]
@@ -55,65 +59,72 @@
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![warn(clippy::almost_complete_letter_range)]
-#![warn(clippy::blacklisted_name)]
-#![warn(clippy::block_in_if_condition_expr)]
-#![warn(clippy::block_in_if_condition_stmt)]
-#![warn(clippy::blocks_in_if_conditions)]
-#![warn(clippy::box_vec)]
-#![warn(clippy::const_static_lifetime)]
-#![warn(clippy::cyclomatic_complexity)]
-#![warn(clippy::derive_hash_xor_eq)]
-#![warn(clippy::disallowed_method)]
-#![warn(clippy::disallowed_type)]
-#![warn(clippy::eval_order_dependence)]
-#![warn(clippy::identity_conversion)]
-#![warn(clippy::if_let_some_result)]
-#![warn(clippy::incorrect_clone_impl_on_copy_type)]
-#![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
-#![warn(clippy::integer_arithmetic)]
-#![warn(clippy::logic_bug)]
-#![warn(clippy::new_without_default_derive)]
-#![warn(clippy::option_and_then_some)]
-#![warn(clippy::option_expect_used)]
-#![warn(clippy::option_map_unwrap_or)]
-#![warn(clippy::option_map_unwrap_or_else)]
-#![warn(clippy::option_unwrap_used)]
-#![warn(clippy::overflow_check_conditional)]
-#![warn(clippy::ref_in_deref)]
-#![warn(clippy::result_expect_used)]
-#![warn(clippy::result_map_unwrap_or_else)]
-#![warn(clippy::result_unwrap_used)]
-#![warn(clippy::single_char_push_str)]
-#![warn(clippy::stutter)]
-#![warn(clippy::thread_local_initializer_can_be_made_const)]
-#![warn(clippy::to_string_in_display)]
-#![warn(clippy::unwrap_or_else_default)]
-#![warn(clippy::zero_width_space)]
-#![warn(clippy::cast_ref_to_mut)]
-#![warn(clippy::clone_double_ref)]
-#![warn(clippy::cmp_nan)]
-#![warn(clippy::drop_bounds)]
-#![warn(clippy::drop_copy)]
-#![warn(clippy::drop_ref)]
-#![warn(clippy::fn_null_check)]
-#![warn(clippy::for_loop_over_option)]
-#![warn(clippy::for_loop_over_result)]
-#![warn(clippy::for_loops_over_fallibles)]
-#![warn(clippy::forget_copy)]
-#![warn(clippy::forget_ref)]
-#![warn(clippy::into_iter_on_array)]
-#![warn(clippy::invalid_atomic_ordering)]
-#![warn(clippy::invalid_ref)]
-#![warn(clippy::invalid_utf8_in_unchecked)]
-#![warn(clippy::let_underscore_drop)]
-#![warn(clippy::mem_discriminant_non_enum)]
-#![warn(clippy::panic_params)]
-#![warn(clippy::positional_named_format_parameters)]
-#![warn(clippy::temporary_cstring_as_ptr)]
-#![warn(clippy::undropped_manually_drops)]
-#![warn(clippy::unknown_clippy_lints)]
-#![warn(clippy::unused_label)]
-#![warn(clippy::vtable_address_comparisons)]
+#![allow(clippy::reversed_empty_ranges)]
+#![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
+#![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
+#![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
+#![warn(clippy::block_in_if_condition_stmt)] //~ ERROR: lint `clippy::block_in_if_condition_stmt`
+#![warn(clippy::blocks_in_if_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions`
+#![warn(clippy::box_vec)] //~ ERROR: lint `clippy::box_vec`
+#![warn(clippy::const_static_lifetime)] //~ ERROR: lint `clippy::const_static_lifetime`
+#![warn(clippy::cyclomatic_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity`
+#![warn(clippy::derive_hash_xor_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq`
+#![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method`
+#![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type`
+#![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence`
+#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
+#![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion`
+#![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
+#![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result`
+#![warn(clippy::incorrect_clone_impl_on_copy_type)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type`
+#![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type`
+#![warn(clippy::integer_arithmetic)] //~ ERROR: lint `clippy::integer_arithmetic`
+#![warn(clippy::logic_bug)] //~ ERROR: lint `clippy::logic_bug`
+#![warn(clippy::new_without_default_derive)] //~ ERROR: lint `clippy::new_without_default_derive`
+#![warn(clippy::option_and_then_some)] //~ ERROR: lint `clippy::option_and_then_some`
+#![warn(clippy::option_expect_used)] //~ ERROR: lint `clippy::option_expect_used`
+#![warn(clippy::option_map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or`
+#![warn(clippy::option_map_unwrap_or_else)] //~ ERROR: lint `clippy::option_map_unwrap_or_else`
+#![warn(clippy::option_unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used`
+#![warn(clippy::overflow_check_conditional)] //~ ERROR: lint `clippy::overflow_check_conditional`
+#![warn(clippy::ref_in_deref)] //~ ERROR: lint `clippy::ref_in_deref`
+#![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used`
+#![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
+#![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str`
+#![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter`
+#![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
+#![warn(clippy::to_string_in_display)] //~ ERROR: lint `clippy::to_string_in_display`
+#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
+#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space`
+#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
+#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
+#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
+#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
+#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
+#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
+#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
+#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
+#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
+#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
+#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy`
+#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref`
+#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array`
+#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
+#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref`
+#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
+#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
+#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg`
+#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
+#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os`
+#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params`
+#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters`
+#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(clippy::undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
+#![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
+#![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
+#![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
+#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index d6637324a03..46d9f0fac59 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> tests/ui/rename.rs:58:9
+  --> tests/ui/rename.rs:63:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,358 +8,394 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> tests/ui/rename.rs:59:9
+  --> tests/ui/rename.rs:64:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:60:9
+  --> tests/ui/rename.rs:65:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:61:9
+  --> tests/ui/rename.rs:66:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:62:9
+  --> tests/ui/rename.rs:67:9
    |
 LL | #![warn(clippy::blocks_in_if_conditions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> tests/ui/rename.rs:63:9
+  --> tests/ui/rename.rs:68:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> tests/ui/rename.rs:64:9
+  --> tests/ui/rename.rs:69:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> tests/ui/rename.rs:65:9
+  --> tests/ui/rename.rs:70:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> tests/ui/rename.rs:66:9
+  --> tests/ui/rename.rs:71:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> tests/ui/rename.rs:67:9
+  --> tests/ui/rename.rs:72:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> tests/ui/rename.rs:68:9
+  --> tests/ui/rename.rs:73:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> tests/ui/rename.rs:69:9
+  --> tests/ui/rename.rs:74:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
+error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
+  --> tests/ui/rename.rs:75:9
+   |
+LL | #![warn(clippy::find_map)]
+   |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
+
+error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
+  --> tests/ui/rename.rs:76:9
+   |
+LL | #![warn(clippy::filter_map)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
+
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:70:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
+error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
+  --> tests/ui/rename.rs:78:9
+   |
+LL | #![warn(clippy::if_let_redundant_pattern_matching)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
+
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:71:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
-  --> tests/ui/rename.rs:72:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
 error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
-  --> tests/ui/rename.rs:73:9
+  --> tests/ui/rename.rs:81:9
    |
 LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> tests/ui/rename.rs:74:9
+  --> tests/ui/rename.rs:82:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> tests/ui/rename.rs:75:9
+  --> tests/ui/rename.rs:83:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> tests/ui/rename.rs:76:9
+  --> tests/ui/rename.rs:84:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> tests/ui/rename.rs:77:9
+  --> tests/ui/rename.rs:85:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:78:9
+  --> tests/ui/rename.rs:86:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:79:9
+  --> tests/ui/rename.rs:87:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:80:9
+  --> tests/ui/rename.rs:88:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:81:9
+  --> tests/ui/rename.rs:89:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
-  --> tests/ui/rename.rs:82:9
+  --> tests/ui/rename.rs:90:9
    |
 LL | #![warn(clippy::overflow_check_conditional)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> tests/ui/rename.rs:83:9
+  --> tests/ui/rename.rs:91:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:84:9
+  --> tests/ui/rename.rs:92:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:85:9
+  --> tests/ui/rename.rs:93:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:86:9
+  --> tests/ui/rename.rs:94:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> tests/ui/rename.rs:87:9
+  --> tests/ui/rename.rs:95:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> tests/ui/rename.rs:88:9
+  --> tests/ui/rename.rs:96:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
-  --> tests/ui/rename.rs:89:9
+  --> tests/ui/rename.rs:97:9
    |
 LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> tests/ui/rename.rs:90:9
+  --> tests/ui/rename.rs:98:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
-  --> tests/ui/rename.rs:91:9
+  --> tests/ui/rename.rs:99:9
    |
 LL | #![warn(clippy::unwrap_or_else_default)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> tests/ui/rename.rs:92:9
+  --> tests/ui/rename.rs:100:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> tests/ui/rename.rs:93:9
+  --> tests/ui/rename.rs:101:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> tests/ui/rename.rs:94:9
+  --> tests/ui/rename.rs:102:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> tests/ui/rename.rs:95:9
+  --> tests/ui/rename.rs:103:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> tests/ui/rename.rs:96:9
+  --> tests/ui/rename.rs:104:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> tests/ui/rename.rs:97:9
+  --> tests/ui/rename.rs:105:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> tests/ui/rename.rs:98:9
+  --> tests/ui/rename.rs:106:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> tests/ui/rename.rs:99:9
+  --> tests/ui/rename.rs:107:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:100:9
+  --> tests/ui/rename.rs:108:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:101:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:102:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> tests/ui/rename.rs:103:9
+  --> tests/ui/rename.rs:111:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> tests/ui/rename.rs:104:9
+  --> tests/ui/rename.rs:112:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> tests/ui/rename.rs:105:9
+  --> tests/ui/rename.rs:113:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> tests/ui/rename.rs:106:9
+  --> tests/ui/rename.rs:114:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> tests/ui/rename.rs:107:9
+  --> tests/ui/rename.rs:115:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> tests/ui/rename.rs:108:9
+  --> tests/ui/rename.rs:116:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> tests/ui/rename.rs:109:9
+  --> tests/ui/rename.rs:117:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
+error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
+  --> tests/ui/rename.rs:118:9
+   |
+LL | #![warn(clippy::maybe_misused_cfg)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
+
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:110:9
+  --> tests/ui/rename.rs:119:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
+error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
+  --> tests/ui/rename.rs:120:9
+   |
+LL | #![warn(clippy::mismatched_target_os)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
+
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:111:9
+  --> tests/ui/rename.rs:121:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> tests/ui/rename.rs:112:9
+  --> tests/ui/rename.rs:122:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> tests/ui/rename.rs:113:9
+  --> tests/ui/rename.rs:123:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> tests/ui/rename.rs:114:9
+  --> tests/ui/rename.rs:124:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> tests/ui/rename.rs:115:9
+  --> tests/ui/rename.rs:125:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> tests/ui/rename.rs:116:9
+  --> tests/ui/rename.rs:126:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
-  --> tests/ui/rename.rs:117:9
+  --> tests/ui/rename.rs:127:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
-error: aborting due to 60 previous errors
+error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
+  --> tests/ui/rename.rs:128:9
+   |
+LL | #![warn(clippy::reverse_range_loop)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
+
+error: aborting due to 66 previous errors
 
diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.rs b/src/tools/clippy/tests/ui/set_contains_or_insert.rs
index 8465007402a..d3a3e1c878b 100644
--- a/src/tools/clippy/tests/ui/set_contains_or_insert.rs
+++ b/src/tools/clippy/tests/ui/set_contains_or_insert.rs
@@ -3,17 +3,78 @@
 #![allow(clippy::needless_borrow)]
 #![warn(clippy::set_contains_or_insert)]
 
-use std::collections::HashSet;
+use std::collections::{BTreeSet, HashSet};
 
-fn main() {
-    should_warn_cases();
+fn should_warn_hashset() {
+    let mut set = HashSet::new();
+    let value = 5;
+
+    if !set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if !set.contains(&value) {
+        set.insert(value);
+    }
 
-    should_not_warn_cases();
+    if !!set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if (&set).contains(&value) {
+        set.insert(value);
+    }
+
+    let borrow_value = &6;
+    if !set.contains(borrow_value) {
+        set.insert(*borrow_value);
+    }
+
+    let borrow_set = &mut set;
+    if !borrow_set.contains(&value) {
+        borrow_set.insert(value);
+    }
 }
 
-fn should_warn_cases() {
+fn should_not_warn_hashset() {
     let mut set = HashSet::new();
     let value = 5;
+    let another_value = 6;
+
+    if !set.contains(&value) {
+        set.insert(another_value);
+    }
+
+    if !set.contains(&value) {
+        println!("Just a comment");
+    }
+
+    if simply_true() {
+        set.insert(value);
+    }
+
+    if !set.contains(&value) {
+        set.replace(value); //it is not insert
+        println!("Just a comment");
+    }
+
+    if set.contains(&value) {
+        println!("value is already in set");
+    } else {
+        set.insert(value);
+    }
+}
+
+fn should_warn_btreeset() {
+    let mut set = BTreeSet::new();
+    let value = 5;
 
     if !set.contains(&value) {
         set.insert(value);
@@ -49,8 +110,8 @@ fn should_warn_cases() {
     }
 }
 
-fn should_not_warn_cases() {
-    let mut set = HashSet::new();
+fn should_not_warn_btreeset() {
+    let mut set = BTreeSet::new();
     let value = 5;
     let another_value = 6;
 
@@ -81,3 +142,11 @@ fn should_not_warn_cases() {
 fn simply_true() -> bool {
     true
 }
+
+// This is placed last in order to be able to add new tests without changing line numbers
+fn main() {
+    should_warn_hashset();
+    should_warn_btreeset();
+    should_not_warn_hashset();
+    should_not_warn_btreeset();
+}
diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
index 507e20964fc..14ad6300544 100644
--- a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
+++ b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
@@ -1,5 +1,5 @@
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:18:13
+  --> tests/ui/set_contains_or_insert.rs:12:13
    |
 LL |     if !set.contains(&value) {
    |             ^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |         set.insert(value);
    = help: to override `-D warnings` add `#[allow(clippy::set_contains_or_insert)]`
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:23:12
+  --> tests/ui/set_contains_or_insert.rs:17:12
    |
 LL |     if set.contains(&value) {
    |            ^^^^^^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL |         set.insert(value);
    |             ^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:28:13
+  --> tests/ui/set_contains_or_insert.rs:22:13
    |
 LL |     if !set.contains(&value) {
    |             ^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |         set.insert(value);
    |             ^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:32:14
+  --> tests/ui/set_contains_or_insert.rs:26:14
    |
 LL |     if !!set.contains(&value) {
    |              ^^^^^^^^^^^^^^^^
@@ -34,7 +34,7 @@ LL |         set.insert(value);
    |             ^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:37:15
+  --> tests/ui/set_contains_or_insert.rs:31:15
    |
 LL |     if (&set).contains(&value) {
    |               ^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ LL |         set.insert(value);
    |             ^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:42:13
+  --> tests/ui/set_contains_or_insert.rs:36:13
    |
 LL |     if !set.contains(borrow_value) {
    |             ^^^^^^^^^^^^^^^^^^^^^^
@@ -50,12 +50,68 @@ LL |         set.insert(*borrow_value);
    |             ^^^^^^^^^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:47:20
+  --> tests/ui/set_contains_or_insert.rs:41:20
    |
 LL |     if !borrow_set.contains(&value) {
    |                    ^^^^^^^^^^^^^^^^
 LL |         borrow_set.insert(value);
    |                    ^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:79:13
+   |
+LL |     if !set.contains(&value) {
+   |             ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:84:12
+   |
+LL |     if set.contains(&value) {
+   |            ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:89:13
+   |
+LL |     if !set.contains(&value) {
+   |             ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:93:14
+   |
+LL |     if !!set.contains(&value) {
+   |              ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:98:15
+   |
+LL |     if (&set).contains(&value) {
+   |               ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:103:13
+   |
+LL |     if !set.contains(borrow_value) {
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+LL |         set.insert(*borrow_value);
+   |             ^^^^^^^^^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:108:20
+   |
+LL |     if !borrow_set.contains(&value) {
+   |                    ^^^^^^^^^^^^^^^^
+LL |         borrow_set.insert(value);
+   |                    ^^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed
index acd70416d8b..5249c440889 100644
--- a/src/tools/clippy/tests/ui/single_match.fixed
+++ b/src/tools/clippy/tests/ui/single_match.fixed
@@ -253,3 +253,46 @@ mod issue8634 {
         }
     }
 }
+
+fn issue11365() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+    use Foo::{A, B, C};
+
+    match Some(A) {
+        Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match Some(A) {
+        Some(A | B) => println!(),
+        Some { 0: C } | None => {},
+    }
+
+    match [A, A] {
+        [A, _] => println!(),
+        [_, A | B | C] => {},
+    }
+
+    match Ok::<_, u32>(Some(A)) {
+        Ok(Some(A)) => println!(),
+        Err(_) | Ok(None | Some(B | C)) => {},
+    }
+
+    if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() }
+
+    match &Some(A) {
+        Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match &Some(A) {
+        &Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    if let Some(A | B) = &Some(A) { println!() }
+}
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index bde78199810..882098a56e7 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -311,3 +311,52 @@ mod issue8634 {
         }
     }
 }
+
+fn issue11365() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+    use Foo::{A, B, C};
+
+    match Some(A) {
+        Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match Some(A) {
+        Some(A | B) => println!(),
+        Some { 0: C } | None => {},
+    }
+
+    match [A, A] {
+        [A, _] => println!(),
+        [_, A | B | C] => {},
+    }
+
+    match Ok::<_, u32>(Some(A)) {
+        Ok(Some(A)) => println!(),
+        Err(_) | Ok(None | Some(B | C)) => {},
+    }
+
+    match Ok::<_, u32>(Some(A)) {
+        Ok(Some(A)) => println!(),
+        Err(_) | Ok(None | Some(_)) => {},
+    }
+
+    match &Some(A) {
+        Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match &Some(A) {
+        &Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match &Some(A) {
+        Some(A | B) => println!(),
+        None | Some(_) => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index a249c120ee4..ceb2a193bf7 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -198,5 +198,23 @@ LL +         }
 LL +     }
    |
 
-error: aborting due to 18 previous errors
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> tests/ui/single_match.rs:343:5
+   |
+LL | /     match Ok::<_, u32>(Some(A)) {
+LL | |         Ok(Some(A)) => println!(),
+LL | |         Err(_) | Ok(None | Some(_)) => {},
+LL | |     }
+   | |_____^ help: try: `if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() }`
+
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> tests/ui/single_match.rs:358:5
+   |
+LL | /     match &Some(A) {
+LL | |         Some(A | B) => println!(),
+LL | |         None | Some(_) => {},
+LL | |     }
+   | |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_match_else.fixed b/src/tools/clippy/tests/ui/single_match_else.fixed
index e840adf0fa3..163be16ad8b 100644
--- a/src/tools/clippy/tests/ui/single_match_else.fixed
+++ b/src/tools/clippy/tests/ui/single_match_else.fixed
@@ -89,7 +89,7 @@ fn main() {
 
     // lint here
     use std::convert::Infallible;
-    if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else {
+    if let Ok(a) = Result::<i32, &Infallible>::Ok(1) { println!("${:?}", a) } else {
         println!("else block");
         return;
     }
diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs
index 430c4da20f1..3f1fd2b3183 100644
--- a/src/tools/clippy/tests/ui/single_match_else.rs
+++ b/src/tools/clippy/tests/ui/single_match_else.rs
@@ -98,7 +98,7 @@ fn main() {
 
     // lint here
     use std::convert::Infallible;
-    match Result::<i32, Infallible>::Ok(1) {
+    match Result::<i32, &Infallible>::Ok(1) {
         Ok(a) => println!("${:?}", a),
         Err(_) => {
             println!("else block");
diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr
index f8f88379d6d..61c348260d0 100644
--- a/src/tools/clippy/tests/ui/single_match_else.stderr
+++ b/src/tools/clippy/tests/ui/single_match_else.stderr
@@ -64,7 +64,7 @@ LL +     }
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
   --> tests/ui/single_match_else.rs:101:5
    |
-LL | /     match Result::<i32, Infallible>::Ok(1) {
+LL | /     match Result::<i32, &Infallible>::Ok(1) {
 LL | |         Ok(a) => println!("${:?}", a),
 LL | |         Err(_) => {
 LL | |             println!("else block");
@@ -75,7 +75,7 @@ LL | |     }
    |
 help: try
    |
-LL ~     if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else {
+LL ~     if let Ok(a) = Result::<i32, &Infallible>::Ok(1) { println!("${:?}", a) } else {
 LL +         println!("else block");
 LL +         return;
 LL +     }
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
index 6ede7bfcd9f..227b98c683e 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -75,8 +75,17 @@ mod std_in_proc_macro_derive {
     struct B {}
 }
 
-fn main() {
-    std_instead_of_core();
-    std_instead_of_alloc();
-    alloc_instead_of_core();
+// Some intrinsics are usable on stable but live in an unstable module, but should still suggest
+// replacing std -> core
+fn intrinsic(a: *mut u8, b: *mut u8) {
+    unsafe {
+        core::intrinsics::copy(a, b, 1);
+        //~^ std_instead_of_core
+    }
 }
+
+#[clippy::msrv = "1.76"]
+fn msrv_1_76(_: std::net::IpAddr) {}
+
+#[clippy::msrv = "1.77"]
+fn msrv_1_77(_: core::net::IpAddr) {}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs
index e22b4f61f3e..01bb78dd3bf 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.rs
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -75,8 +75,17 @@ mod std_in_proc_macro_derive {
     struct B {}
 }
 
-fn main() {
-    std_instead_of_core();
-    std_instead_of_alloc();
-    alloc_instead_of_core();
+// Some intrinsics are usable on stable but live in an unstable module, but should still suggest
+// replacing std -> core
+fn intrinsic(a: *mut u8, b: *mut u8) {
+    unsafe {
+        std::intrinsics::copy(a, b, 1);
+        //~^ std_instead_of_core
+    }
 }
+
+#[clippy::msrv = "1.76"]
+fn msrv_1_76(_: std::net::IpAddr) {}
+
+#[clippy::msrv = "1.77"]
+fn msrv_1_77(_: std::net::IpAddr) {}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
index 22cb9db7050..45d60d235ce 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
@@ -85,5 +85,17 @@ LL |     use alloc::slice::from_ref;
    = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]`
 
-error: aborting due to 13 previous errors
+error: used import from `std` instead of `core`
+  --> tests/ui/std_instead_of_core.rs:82:9
+   |
+LL |         std::intrinsics::copy(a, b, 1);
+   |         ^^^ help: consider importing the item from `core`: `core`
+
+error: used import from `std` instead of `core`
+  --> tests/ui/std_instead_of_core.rs:91:17
+   |
+LL | fn msrv_1_77(_: std::net::IpAddr) {}
+   |                 ^^^ help: consider importing the item from `core`: `core`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
index 4faf0237c17..43b03676b1d 100644
--- a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
@@ -2,51 +2,84 @@ error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:19:13
    |
 LL |     let _ = 2 ^ 5;
-   |             ^^^^^ help: did you mean to write: `2.pow(5)`
+   |             ^^^^^
    |
    = note: `-D clippy::suspicious-xor-used-as-pow` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::suspicious_xor_used_as_pow)]`
+help: did you mean to write
+   |
+LL |     let _ = 2.pow(5);
+   |             ~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:22:13
    |
 LL |     let _ = 2i32 ^ 9i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(9i32)`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 2i32.pow(9i32);
+   |             ~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:24:13
    |
 LL |     let _ = 2i32 ^ 2i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(2i32)`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 2i32.pow(2i32);
+   |             ~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:26:13
    |
 LL |     let _ = 50i32 ^ 3i32;
-   |             ^^^^^^^^^^^^ help: did you mean to write: `50i32.pow(3i32)`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 50i32.pow(3i32);
+   |             ~~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:28:13
    |
 LL |     let _ = 5i32 ^ 8i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `5i32.pow(8i32)`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 5i32.pow(8i32);
+   |             ~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:30:13
    |
 LL |     let _ = 2i32 ^ 32i32;
-   |             ^^^^^^^^^^^^ help: did you mean to write: `2i32.pow(32i32)`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 2i32.pow(32i32);
+   |             ~~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:13:9
    |
 LL |         1 ^ 2 // should warn even if inside macro
-   |         ^^^^^ help: did you mean to write: `1.pow(2)`
+   |         ^^^^^
 ...
 LL |     macro_test_inside!();
    |     -------------------- in this macro invocation
    |
    = note: this error originates in the macro `macro_test_inside` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: did you mean to write
+   |
+LL |         1.pow(2) // should warn even if inside macro
+   |         ~~~~~~~~
 
 error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed
index aae4f8ac47f..f149bfb7774 100644
--- a/src/tools/clippy/tests/ui/try_err.fixed
+++ b/src/tools/clippy/tests/ui/try_err.fixed
@@ -1,5 +1,5 @@
 //@aux-build:proc_macros.rs
-
+#![feature(try_blocks)]
 #![deny(clippy::try_err)]
 #![allow(
     clippy::unnecessary_wraps,
@@ -152,3 +152,11 @@ pub fn try_return(x: bool) -> Result<i32, i32> {
     }
     Ok(0)
 }
+
+// Test that the lint is suppressed in try block.
+pub fn try_block() -> Result<(), i32> {
+    let _: Result<_, i32> = try {
+        Err(1)?;
+    };
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs
index 927eccf2d54..841ec6b5d5c 100644
--- a/src/tools/clippy/tests/ui/try_err.rs
+++ b/src/tools/clippy/tests/ui/try_err.rs
@@ -1,5 +1,5 @@
 //@aux-build:proc_macros.rs
-
+#![feature(try_blocks)]
 #![deny(clippy::try_err)]
 #![allow(
     clippy::unnecessary_wraps,
@@ -152,3 +152,11 @@ pub fn try_return(x: bool) -> Result<i32, i32> {
     }
     Ok(0)
 }
+
+// Test that the lint is suppressed in try block.
+pub fn try_block() -> Result<(), i32> {
+    let _: Result<_, i32> = try {
+        Err(1)?;
+    };
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/uninit_vec.rs b/src/tools/clippy/tests/ui/uninit_vec.rs
index c069b9adf2d..0cc77a8775d 100644
--- a/src/tools/clippy/tests/ui/uninit_vec.rs
+++ b/src/tools/clippy/tests/ui/uninit_vec.rs
@@ -1,5 +1,6 @@
 #![warn(clippy::uninit_vec)]
 
+use std::cell::UnsafeCell;
 use std::mem::MaybeUninit;
 
 #[derive(Default)]
@@ -12,6 +13,12 @@ union MyOwnMaybeUninit {
     uninit: (),
 }
 
+// https://github.com/rust-lang/rust/issues/119620
+unsafe fn requires_paramenv<S>() {
+    let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1);
+    vec.set_len(1);
+}
+
 fn main() {
     // with_capacity() -> set_len() should be detected
     let mut vec: Vec<u8> = Vec::with_capacity(1000);
diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr
index 8e93466c2cc..e8b77d653f0 100644
--- a/src/tools/clippy/tests/ui/uninit_vec.stderr
+++ b/src/tools/clippy/tests/ui/uninit_vec.stderr
@@ -1,5 +1,17 @@
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:17:5
+  --> tests/ui/uninit_vec.rs:18:5
+   |
+LL |     let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     vec.set_len(1);
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+   = note: `-D clippy::uninit-vec` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::uninit_vec)]`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> tests/ui/uninit_vec.rs:24:5
    |
 LL |     let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,11 +20,9 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
    |
    = help: initialize the buffer or wrap the content in `MaybeUninit`
-   = note: `-D clippy::uninit-vec` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::uninit_vec)]`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:24:5
+  --> tests/ui/uninit_vec.rs:31:5
    |
 LL |     vec.reserve(1000);
    |     ^^^^^^^^^^^^^^^^^^
@@ -23,7 +33,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> tests/ui/uninit_vec.rs:31:5
+  --> tests/ui/uninit_vec.rs:38:5
    |
 LL |     let mut vec: Vec<u8> = Vec::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +42,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> tests/ui/uninit_vec.rs:38:5
+  --> tests/ui/uninit_vec.rs:45:5
    |
 LL |     let mut vec: Vec<u8> = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +51,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> tests/ui/uninit_vec.rs:44:5
+  --> tests/ui/uninit_vec.rs:51:5
    |
 LL |     let mut vec: Vec<u8> = Vec::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +60,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:61:5
+  --> tests/ui/uninit_vec.rs:68:5
    |
 LL |     let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,7 +71,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:71:5
+  --> tests/ui/uninit_vec.rs:78:5
    |
 LL |     my_vec.vec.reserve(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +82,7 @@ LL |         my_vec.vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:77:5
+  --> tests/ui/uninit_vec.rs:84:5
    |
 LL |     my_vec.vec = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +93,7 @@ LL |         my_vec.vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:52:9
+  --> tests/ui/uninit_vec.rs:59:9
    |
 LL |         let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +104,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:56:9
+  --> tests/ui/uninit_vec.rs:63:9
    |
 LL |         vec.reserve(1000);
    |         ^^^^^^^^^^^^^^^^^^
@@ -105,7 +115,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:132:9
+  --> tests/ui/uninit_vec.rs:139:9
    |
 LL |         let mut vec: Vec<T> = Vec::with_capacity(1000);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -115,5 +125,5 @@ LL |             vec.set_len(10);
    |
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unneeded_field_pattern.rs b/src/tools/clippy/tests/ui/unneeded_field_pattern.rs
index 0dc21f4ce94..1d42f81711b 100644
--- a/src/tools/clippy/tests/ui/unneeded_field_pattern.rs
+++ b/src/tools/clippy/tests/ui/unneeded_field_pattern.rs
@@ -1,6 +1,6 @@
 //@aux-build:proc_macros.rs
 #![warn(clippy::unneeded_field_pattern)]
-#![allow(dead_code, unused)]
+#![allow(dead_code, unused, clippy::single_match)]
 
 #[macro_use]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/unused_result_ok.fixed b/src/tools/clippy/tests/ui/unused_result_ok.fixed
new file mode 100644
index 00000000000..e78fde5c9e3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_result_ok.fixed
@@ -0,0 +1,40 @@
+//@aux-build:proc_macros.rs
+#![warn(clippy::unused_result_ok)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn bad_style(x: &str) {
+    let _ = x.parse::<u32>();
+}
+
+fn good_style(x: &str) -> Option<u32> {
+    x.parse::<u32>().ok()
+}
+
+#[rustfmt::skip]
+fn strange_parse(x: &str) {
+    let _ = x   .   parse::<i32>();
+}
+
+macro_rules! v {
+    () => {
+        Ok::<(), ()>(())
+    };
+}
+
+macro_rules! w {
+    () => {
+        let _ = Ok::<(), ()>(());
+    };
+}
+
+fn main() {
+    let _ = v!();
+    w!();
+
+    external! {
+        Ok::<(),()>(()).ok();
+    };
+}
diff --git a/src/tools/clippy/tests/ui/unused_result_ok.rs b/src/tools/clippy/tests/ui/unused_result_ok.rs
new file mode 100644
index 00000000000..117d64c4cec
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_result_ok.rs
@@ -0,0 +1,40 @@
+//@aux-build:proc_macros.rs
+#![warn(clippy::unused_result_ok)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn bad_style(x: &str) {
+    x.parse::<u32>().ok();
+}
+
+fn good_style(x: &str) -> Option<u32> {
+    x.parse::<u32>().ok()
+}
+
+#[rustfmt::skip]
+fn strange_parse(x: &str) {
+    x   .   parse::<i32>()   .   ok   ();
+}
+
+macro_rules! v {
+    () => {
+        Ok::<(), ()>(())
+    };
+}
+
+macro_rules! w {
+    () => {
+        Ok::<(), ()>(()).ok();
+    };
+}
+
+fn main() {
+    v!().ok();
+    w!();
+
+    external! {
+        Ok::<(),()>(()).ok();
+    };
+}
diff --git a/src/tools/clippy/tests/ui/unused_result_ok.stderr b/src/tools/clippy/tests/ui/unused_result_ok.stderr
new file mode 100644
index 00000000000..241e0c71261
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_result_ok.stderr
@@ -0,0 +1,52 @@
+error: ignoring a result with `.ok()` is misleading
+  --> tests/ui/unused_result_ok.rs:9:5
+   |
+LL |     x.parse::<u32>().ok();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unused-result-ok` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unused_result_ok)]`
+help: consider using `let _ =` and removing the call to `.ok()` instead
+   |
+LL |     let _ = x.parse::<u32>();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: ignoring a result with `.ok()` is misleading
+  --> tests/ui/unused_result_ok.rs:18:5
+   |
+LL |     x   .   parse::<i32>()   .   ok   ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `let _ =` and removing the call to `.ok()` instead
+   |
+LL |     let _ = x   .   parse::<i32>();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: ignoring a result with `.ok()` is misleading
+  --> tests/ui/unused_result_ok.rs:34:5
+   |
+LL |     v!().ok();
+   |     ^^^^^^^^^
+   |
+help: consider using `let _ =` and removing the call to `.ok()` instead
+   |
+LL |     let _ = v!();
+   |     ~~~~~~~~~~~~
+
+error: ignoring a result with `.ok()` is misleading
+  --> tests/ui/unused_result_ok.rs:29:9
+   |
+LL |         Ok::<(), ()>(()).ok();
+   |         ^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     w!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `w` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using `let _ =` and removing the call to `.ok()` instead
+   |
+LL |         let _ = Ok::<(), ()>(());
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
index 96368a07053..a56bd0a8d07 100644
--- a/src/tools/clippy/tests/ui/unwrap_expect_used.rs
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
@@ -31,7 +31,7 @@ fn main() {
 
     // Don't trigger on unwrap_err on an option
     Some(3).unwrap_err();
-    Some(3).expect_err("Hellow none!");
+    Some(3).expect_err("Hello none!");
 
     // Issue #11245: The `Err` variant can never be constructed so do not lint this.
     let x: Result<(), !> = Ok(());
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
index 59b5c858d04..b8087c6e000 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
@@ -456,6 +456,15 @@ fn fn_once_closure() {
     });
 }
 
+fn issue13123() {
+    let mut it = 0..20;
+    'label: for n in it {
+        if n % 25 == 0 {
+            break 'label;
+        }
+    }
+}
+
 fn main() {
     let mut it = 0..20;
     for _ in it {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
index 559513d5694..8e02f59b512 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
@@ -456,6 +456,15 @@ fn fn_once_closure() {
     });
 }
 
+fn issue13123() {
+    let mut it = 0..20;
+    'label: while let Some(n) = it.next() {
+        if n % 25 == 0 {
+            break 'label;
+        }
+    }
+}
+
 fn main() {
     let mut it = 0..20;
     while let Some(..) = it.next() {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
index 8ff1f23644b..d96b26acf34 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
@@ -160,8 +160,14 @@ LL |         while let Some(x) = it.next() {
 error: this loop could be written as a `for` loop
   --> tests/ui/while_let_on_iterator.rs:461:5
    |
+LL |     'label: while let Some(n) = it.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'label: for n in it`
+
+error: this loop could be written as a `for` loop
+  --> tests/ui/while_let_on_iterator.rs:470:5
+   |
 LL |     while let Some(..) = it.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
 
-error: aborting due to 27 previous errors
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs
index eba5405e67e..68328333937 100644
--- a/src/tools/clippy/tests/versioncheck.rs
+++ b/src/tools/clippy/tests/versioncheck.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::single_match_else)]
 
diff --git a/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml b/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml
index 85a91cd2dec..98b4fb7aa50 100644
--- a/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml
+++ b/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml
@@ -1,3 +1,6 @@
 [package]
 name = "path_dep"
 version = "0.1.0"
+
+[features]
+primary_package_test = []
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index 0c0f28e4fbd..300c9de178f 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -541,7 +541,7 @@ Otherwise, have a great day =^.^=
                     <div class="col-12 col-md-5 search-control">
                         <div class="input-group">
                             <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label>
-                            <input type="text" class="form-control filter-input" placeholder="Keywords or search string" id="search-input"
+                            <input type="text" class="form-control filter-input" placeholder="Keywords or search string (`S` or `/` to focus)" id="search-input"
                                 ng-model="search" ng-blur="updatePath()" ng-keyup="$event.keyCode == 13 && updatePath()"
                                 ng-model-options="{debounce: 50}" />
                             <span class="input-group-btn">
@@ -605,7 +605,7 @@ Otherwise, have a great day =^.^=
                             <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
                         </div>
                         <!-- Jump to source -->
-                        <div class="lint-additional-info-item">
+                        <div class="lint-additional-info-item" ng-if="lint.id_span">
                             <a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/clippy_lints/{{lint.id_span.path}}#L{{lint.id_span.line}}">View Source</a>
                         </div>
                     </div>
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index 661f80a6d34..ed1e090e1b5 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -1,5 +1,5 @@
 (function () {
-    var md = window.markdownit({
+    const md = window.markdownit({
         html: true,
         linkify: true,
         typographer: true,
@@ -17,7 +17,7 @@
     });
 
     function scrollToLint(lintId) {
-        var target = document.getElementById(lintId);
+        const target = document.getElementById(lintId);
         if (!target) {
             return;
         }
@@ -25,21 +25,17 @@
     }
 
     function scrollToLintByURL($scope, $location) {
-        var removeListener = $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
+        const removeListener = $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
             scrollToLint($location.path().substring(1));
             removeListener();
         });
     }
 
     function selectGroup($scope, selectedGroup) {
-        var groups = $scope.groups;
-        for (var group in groups) {
+        const groups = $scope.groups;
+        for (const group in groups) {
             if (groups.hasOwnProperty(group)) {
-                if (group === selectedGroup) {
-                    groups[group] = true;
-                } else {
-                    groups[group] = false;
-                }
+                groups[group] = group === selectedGroup;
             }
         }
     }
@@ -108,7 +104,7 @@
         })
         .controller("lintList", function ($scope, $http, $location, $timeout) {
             // Level filter
-            var LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
+            const LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
             $scope.levels = { ...LEVEL_FILTERS_DEFAULT };
             $scope.byLevels = function (lint) {
                 return $scope.levels[lint.level];
@@ -367,7 +363,7 @@
             }
 
             $scope.clearVersionFilters = function () {
-                for (let filter in $scope.versionFilters) {
+                for (const filter in $scope.versionFilters) {
                     $scope.versionFilters[filter] = { enabled: false, minorVersion: null };
                 }
             }
@@ -378,7 +374,7 @@
 
             $scope.updateVersionFilters = function() {
                 for (const filter in $scope.versionFilters) {
-                    let minorVersion = $scope.versionFilters[filter].minorVersion;
+                    const minorVersion = $scope.versionFilters[filter].minorVersion;
 
                     // 1.29.0 and greater
                     if (minorVersion && minorVersion > 28) {
@@ -391,14 +387,14 @@
             }
 
             $scope.byVersion = function(lint) {
-                let filters = $scope.versionFilters;
+                const filters = $scope.versionFilters;
                 for (const filter in filters) {
                     if (filters[filter].enabled) {
-                        let minorVersion = filters[filter].minorVersion;
+                        const minorVersion = filters[filter].minorVersion;
 
                         // Strip the "pre " prefix for pre 1.29.0 lints
-                        let lintVersion = lint.version.startsWith("pre ") ? lint.version.substring(4, lint.version.length) : lint.version;
-                        let lintMinorVersion = lintVersion.substring(2, 4);
+                        const lintVersion = lint.version.startsWith("pre ") ? lint.version.substring(4, lint.version.length) : lint.version;
+                        const lintMinorVersion = lintVersion.substring(2, 4);
 
                         switch (filter) {
                             // "=" gets the highest priority, since all filters are inclusive
@@ -441,8 +437,8 @@
 
                 // Search the description
                 // The use of `for`-loops instead of `foreach` enables us to return early
-                let terms = searchStr.split(" ");
-                let docsLowerCase = lint.docs.toLowerCase();
+                const terms = searchStr.split(" ");
+                const docsLowerCase = lint.docs.toLowerCase();
                 for (index = 0; index < terms.length; index++) {
                     // This is more likely and will therefore be checked first
                     if (docsLowerCase.indexOf(terms[index]) !== -1) {
@@ -479,7 +475,7 @@
                 const clipboard = document.getElementById("clipboard-" + lint.id);
                 if (clipboard) {
                     let resetClipboardTimeout = null;
-                    let resetClipboardIcon = clipboard.innerHTML;
+                    const resetClipboardIcon = clipboard.innerHTML;
 
                     function resetClipboard() {
                         resetClipboardTimeout = null;
@@ -511,7 +507,7 @@
                     $scope.data = data;
                     $scope.loading = false;
 
-                    var selectedGroup = getQueryVariable("sel");
+                    const selectedGroup = getQueryVariable("sel");
                     if (selectedGroup) {
                         selectGroup($scope, selectedGroup.toLowerCase());
                     }
@@ -519,7 +515,7 @@
                     scrollToLintByURL($scope, $location);
 
                     setTimeout(function () {
-                        var el = document.getElementById('filter-input');
+                        const el = document.getElementById('filter-input');
                         if (el) { el.focus() }
                     }, 0);
                 })
@@ -531,10 +527,10 @@
 })();
 
 function getQueryVariable(variable) {
-    var query = window.location.search.substring(1);
-    var vars = query.split('&');
-    for (var i = 0; i < vars.length; i++) {
-        var pair = vars[i].split('=');
+    const query = window.location.search.substring(1);
+    const vars = query.split('&');
+    for (const entry of vars) {
+        const pair = entry.split('=');
         if (decodeURIComponent(pair[0]) == variable) {
             return decodeURIComponent(pair[1]);
         }
@@ -579,6 +575,32 @@ function setTheme(theme, store) {
     }
 }
 
+function handleShortcut(ev) {
+    if (ev.ctrlKey || ev.altKey || ev.metaKey) {
+        return;
+    }
+
+    if (document.activeElement.tagName === "INPUT") {
+        if (ev.key === "Escape") {
+            document.activeElement.blur();
+        }
+    } else {
+        switch (ev.key) {
+            case "s":
+            case "S":
+            case "/":
+                ev.preventDefault(); // To prevent the key to be put into the input.
+                document.getElementById("search-input").focus();
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+document.addEventListener("keypress", handleShortcut);
+document.addEventListener("keydown", handleShortcut);
+
 // loading the theme after the initial load
 const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
 const theme = localStorage.getItem('clippy-lint-list-theme');
diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml
index d0820cfc2a0..edf9e5c5393 100644
--- a/src/tools/collect-license-metadata/Cargo.toml
+++ b/src/tools/collect-license-metadata/Cargo.toml
@@ -2,6 +2,8 @@
 name = "collect-license-metadata"
 version = "0.1.0"
 edition = "2021"
+description = "Runs the reuse tool and caches the output, so rust toolchain devs don't need to have reuse installed"
+license = "MIT OR Apache-2.0"
 
 [dependencies]
 anyhow = "1.0.65"
diff --git a/src/tools/collect-license-metadata/src/main.rs b/src/tools/collect-license-metadata/src/main.rs
index ca6aa01d78c..dce36bb17b6 100644
--- a/src/tools/collect-license-metadata/src/main.rs
+++ b/src/tools/collect-license-metadata/src/main.rs
@@ -8,6 +8,11 @@ use anyhow::Error;
 
 use crate::licenses::LicensesInterner;
 
+/// The entry point to the binary.
+///
+/// You should probably let `bootstrap` execute this program instead of running it directly.
+///
+/// Run `x.py run collect-license-metadata`
 fn main() -> Result<(), Error> {
     let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into();
     let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into();
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs
index 288f90ea123..50c909793f5 100644
--- a/src/tools/compiletest/src/command-list.rs
+++ b/src/tools/compiletest/src/command-list.rs
@@ -18,6 +18,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "check-test-line-numbers-match",
     "compare-output-lines-by-subset",
     "compile-flags",
+    "doc-flags",
     "dont-check-compiler-stderr",
     "dont-check-compiler-stdout",
     "dont-check-failure-status",
@@ -169,6 +170,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-32bit",
     "only-64bit",
     "only-aarch64",
+    "only-aarch64-unknown-linux-gnu",
     "only-apple",
     "only-arm",
     "only-avr",
@@ -203,6 +205,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-watchos",
     "only-windows",
     "only-windows-gnu",
+    "only-windows-msvc",
     "only-x86",
     "only-x86_64",
     "only-x86_64-fortanix-unknown-sgx",
@@ -226,6 +229,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "should-ice",
     "stderr-per-bitwidth",
     "test-mir-pass",
+    "unique-doc-out-dir",
     "unset-exec-env",
     "unset-rustc-env",
     // Used by the tidy check `unknown_revision`.
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index cde3e3295c6..1fc24301c85 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -95,6 +95,8 @@ pub struct TestProps {
     pub compile_flags: Vec<String>,
     // Extra flags to pass when the compiled code is run (such as --bench)
     pub run_flags: Vec<String>,
+    /// Extra flags to pass to rustdoc but not the compiler.
+    pub doc_flags: Vec<String>,
     // If present, the name of a file that this test should match when
     // pretty-printed
     pub pp_exact: Option<PathBuf>,
@@ -122,6 +124,9 @@ pub struct TestProps {
     pub unset_exec_env: Vec<String>,
     // Build documentation for all specified aux-builds as well
     pub build_aux_docs: bool,
+    /// Build the documentation for each crate in a unique output directory.
+    /// Uses <root output directory>/docs/<test name>/doc
+    pub unique_doc_out_dir: bool,
     // Flag to force a crate to be built with the host architecture
     pub force_host: bool,
     // Check stdout for error-pattern output as well as stderr
@@ -220,8 +225,10 @@ mod directives {
     pub const REGEX_ERROR_PATTERN: &'static str = "regex-error-pattern";
     pub const COMPILE_FLAGS: &'static str = "compile-flags";
     pub const RUN_FLAGS: &'static str = "run-flags";
+    pub const DOC_FLAGS: &'static str = "doc-flags";
     pub const SHOULD_ICE: &'static str = "should-ice";
     pub const BUILD_AUX_DOCS: &'static str = "build-aux-docs";
+    pub const UNIQUE_DOC_OUT_DIR: &'static str = "unique-doc-out-dir";
     pub const FORCE_HOST: &'static str = "force-host";
     pub const CHECK_STDOUT: &'static str = "check-stdout";
     pub const CHECK_RUN_RESULTS: &'static str = "check-run-results";
@@ -267,6 +274,7 @@ impl TestProps {
             regex_error_patterns: vec![],
             compile_flags: vec![],
             run_flags: vec![],
+            doc_flags: vec![],
             pp_exact: None,
             aux_builds: vec![],
             aux_bins: vec![],
@@ -281,6 +289,7 @@ impl TestProps {
             exec_env: vec![],
             unset_exec_env: vec![],
             build_aux_docs: false,
+            unique_doc_out_dir: false,
             force_host: false,
             check_stdout: false,
             check_run_results: false,
@@ -378,6 +387,8 @@ impl TestProps {
                         |r| r,
                     );
 
+                    config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r);
+
                     fn split_flags(flags: &str) -> Vec<String> {
                         // Individual flags can be single-quoted to preserve spaces; see
                         // <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>.
@@ -415,6 +426,8 @@ impl TestProps {
 
                     config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
                     config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs);
+                    config.set_name_directive(ln, UNIQUE_DOC_OUT_DIR, &mut self.unique_doc_out_dir);
+
                     config.set_name_directive(ln, FORCE_HOST, &mut self.force_host);
                     config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout);
                     config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results);
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 1f15605d8be..b1b6d6fc8eb 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1,5 +1,6 @@
 // ignore-tidy-filelength
 
+use std::borrow::Cow;
 use std::collections::{HashMap, HashSet};
 use std::ffi::{OsStr, OsString};
 use std::fs::{self, create_dir_all, File, OpenOptions};
@@ -723,7 +724,7 @@ impl<'test> TestCx<'test> {
         self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
         rustc.args(&self.props.compile_flags);
 
-        self.compose_and_run_compiler(rustc, Some(src))
+        self.compose_and_run_compiler(rustc, Some(src), self.testpaths)
     }
 
     fn run_debuginfo_test(&self) {
@@ -1579,13 +1580,15 @@ impl<'test> TestCx<'test> {
             passes,
         );
 
-        self.compose_and_run_compiler(rustc, None)
+        self.compose_and_run_compiler(rustc, None, self.testpaths)
     }
 
-    fn document(&self, out_dir: &Path) -> ProcRes {
+    /// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run.
+    /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths.
+    fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
         if self.props.build_aux_docs {
             for rel_ab in &self.props.aux_builds {
-                let aux_testpaths = self.compute_aux_test_paths(&self.testpaths, rel_ab);
+                let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab);
                 let aux_props =
                     self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
                 let aux_cx = TestCx {
@@ -1596,7 +1599,9 @@ impl<'test> TestCx<'test> {
                 };
                 // Create the directory for the stdout/stderr files.
                 create_dir_all(aux_cx.output_base_dir()).unwrap();
-                let auxres = aux_cx.document(out_dir);
+                // use root_testpaths here, because aux-builds should have the
+                // same --out-dir and auxiliary directory.
+                let auxres = aux_cx.document(&root_out_dir, root_testpaths);
                 if !auxres.status.success() {
                     return auxres;
                 }
@@ -1606,21 +1611,40 @@ impl<'test> TestCx<'test> {
         let aux_dir = self.aux_output_dir_name();
 
         let rustdoc_path = self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed");
-        let mut rustdoc = Command::new(rustdoc_path);
 
+        // actual --out-dir given to the auxiliary or test, as opposed to the root out dir for the entire
+        // test
+        let out_dir: Cow<'_, Path> = if self.props.unique_doc_out_dir {
+            let file_name = self.testpaths.file.file_stem().expect("file name should not be empty");
+            let out_dir = PathBuf::from_iter([
+                root_out_dir,
+                Path::new("docs"),
+                Path::new(file_name),
+                Path::new("doc"),
+            ]);
+            create_dir_all(&out_dir).unwrap();
+            Cow::Owned(out_dir)
+        } else {
+            Cow::Borrowed(root_out_dir)
+        };
+
+        let mut rustdoc = Command::new(rustdoc_path);
+        let current_dir = output_base_dir(self.config, root_testpaths, self.safe_revision());
+        rustdoc.current_dir(current_dir);
         rustdoc
             .arg("-L")
             .arg(self.config.run_lib_path.to_str().unwrap())
             .arg("-L")
             .arg(aux_dir)
             .arg("-o")
-            .arg(out_dir)
+            .arg(out_dir.as_ref())
             .arg("--deny")
             .arg("warnings")
             .arg(&self.testpaths.file)
             .arg("-A")
             .arg("internal_features")
-            .args(&self.props.compile_flags);
+            .args(&self.props.compile_flags)
+            .args(&self.props.doc_flags);
 
         if self.config.mode == RustdocJson {
             rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options");
@@ -1630,7 +1654,7 @@ impl<'test> TestCx<'test> {
             rustdoc.arg(format!("-Clinker={}", linker));
         }
 
-        self.compose_and_run_compiler(rustdoc, None)
+        self.compose_and_run_compiler(rustdoc, None, root_testpaths)
     }
 
     fn exec_compiled_test(&self) -> ProcRes {
@@ -1828,9 +1852,16 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
+    /// `root_testpaths` refers to the path of the original test.
+    /// the auxiliary and the test with an aux-build have the same `root_testpaths`.
+    fn compose_and_run_compiler(
+        &self,
+        mut rustc: Command,
+        input: Option<String>,
+        root_testpaths: &TestPaths,
+    ) -> ProcRes {
         let aux_dir = self.aux_output_dir();
-        self.build_all_auxiliary(&self.testpaths, &aux_dir, &mut rustc);
+        self.build_all_auxiliary(root_testpaths, &aux_dir, &mut rustc);
 
         rustc.envs(self.props.rustc_env.clone());
         self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove);
@@ -2545,7 +2576,7 @@ impl<'test> TestCx<'test> {
             Vec::new(),
         );
 
-        let proc_res = self.compose_and_run_compiler(rustc, None);
+        let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
         let output_path = self.get_filecheck_file("ll");
         (proc_res, output_path)
     }
@@ -2581,7 +2612,7 @@ impl<'test> TestCx<'test> {
             Vec::new(),
         );
 
-        let proc_res = self.compose_and_run_compiler(rustc, None);
+        let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
         let output_path = self.get_filecheck_file("s");
         (proc_res, output_path)
     }
@@ -2664,7 +2695,7 @@ impl<'test> TestCx<'test> {
         let out_dir = self.output_base_dir();
         remove_and_create_dir_all(&out_dir);
 
-        let proc_res = self.document(&out_dir);
+        let proc_res = self.document(&out_dir, &self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc failed!", &proc_res);
         }
@@ -2723,7 +2754,7 @@ impl<'test> TestCx<'test> {
         let aux_dir = new_rustdoc.aux_output_dir();
         new_rustdoc.build_all_auxiliary(&new_rustdoc.testpaths, &aux_dir, &mut rustc);
 
-        let proc_res = new_rustdoc.document(&compare_dir);
+        let proc_res = new_rustdoc.document(&compare_dir, &new_rustdoc.testpaths);
         if !proc_res.status.success() {
             eprintln!("failed to run nightly rustdoc");
             return;
@@ -2847,7 +2878,7 @@ impl<'test> TestCx<'test> {
         let out_dir = self.output_base_dir();
         remove_and_create_dir_all(&out_dir);
 
-        let proc_res = self.document(&out_dir);
+        let proc_res = self.document(&out_dir, &self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc failed!", &proc_res);
         }
@@ -2923,31 +2954,24 @@ impl<'test> TestCx<'test> {
     fn check_rustdoc_test_option(&self, res: ProcRes) {
         let mut other_files = Vec::new();
         let mut files: HashMap<String, Vec<usize>> = HashMap::new();
-        let cwd = env::current_dir().unwrap();
-        files.insert(
-            self.testpaths
-                .file
-                .strip_prefix(&cwd)
-                .unwrap_or(&self.testpaths.file)
-                .to_str()
-                .unwrap()
-                .replace('\\', "/"),
-            self.get_lines(&self.testpaths.file, Some(&mut other_files)),
-        );
+        let normalized = fs::canonicalize(&self.testpaths.file).expect("failed to canonicalize");
+        let normalized = normalized.to_str().unwrap().replace('\\', "/");
+        files.insert(normalized, self.get_lines(&self.testpaths.file, Some(&mut other_files)));
         for other_file in other_files {
             let mut path = self.testpaths.file.clone();
             path.set_file_name(&format!("{}.rs", other_file));
-            files.insert(
-                path.strip_prefix(&cwd).unwrap_or(&path).to_str().unwrap().replace('\\', "/"),
-                self.get_lines(&path, None),
-            );
+            let path = fs::canonicalize(path).expect("failed to canonicalize");
+            let normalized = path.to_str().unwrap().replace('\\', "/");
+            files.insert(normalized, self.get_lines(&path, None));
         }
 
         let mut tested = 0;
         for _ in res.stdout.split('\n').filter(|s| s.starts_with("test ")).inspect(|s| {
             if let Some((left, right)) = s.split_once(" - ") {
                 let path = left.rsplit("test ").next().unwrap();
-                if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) {
+                let path = fs::canonicalize(&path).expect("failed to canonicalize");
+                let path = path.to_str().unwrap().replace('\\', "/");
+                if let Some(ref mut v) = files.get_mut(&path) {
                     tested += 1;
                     let mut iter = right.split("(line ");
                     iter.next();
@@ -3779,7 +3803,7 @@ impl<'test> TestCx<'test> {
         if let Some(nodejs) = &self.config.nodejs {
             let out_dir = self.output_base_dir();
 
-            self.document(&out_dir);
+            self.document(&out_dir, &self.testpaths);
 
             let root = self.config.find_rust_src_root().unwrap();
             let file_stem =
@@ -4095,7 +4119,7 @@ impl<'test> TestCx<'test> {
                 rustc.arg(crate_name);
             }
 
-            let res = self.compose_and_run_compiler(rustc, None);
+            let res = self.compose_and_run_compiler(rustc, None, self.testpaths);
             if !res.status.success() {
                 self.fatal_proc_rec("failed to compile fixed code", &res);
             }
diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs
index 6ee147da5a9..05191a15980 100644
--- a/src/tools/compiletest/src/runtest/coverage.rs
+++ b/src/tools/compiletest/src/runtest/coverage.rs
@@ -191,7 +191,7 @@ impl<'test> TestCx<'test> {
 
         rustdoc_cmd.arg(&self.testpaths.file);
 
-        let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None);
+        let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None, self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
         }
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index 899ef0f8a6c..404101abd41 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -2,10 +2,14 @@
 name = "generate-copyright"
 version = "0.1.0"
 edition = "2021"
+description = "Produces a manifest of all the copyrighted materials in the Rust Toolchain"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
 anyhow = "1.0.65"
+cargo_metadata = "0.18.1"
+rinja = "0.3.0"
 serde = { version = "1.0.147", features = ["derive"] }
 serde_json = "1.0.85"
+thiserror = "1"
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
new file mode 100644
index 00000000000..c85e4aa371a
--- /dev/null
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -0,0 +1,191 @@
+//! Gets metadata about a workspace from Cargo
+
+use std::collections::BTreeMap;
+use std::ffi::OsStr;
+use std::path::{Path, PathBuf};
+
+/// Describes how this module can fail
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    #[error("I/O Error: {0:?}")]
+    Io(#[from] std::io::Error),
+    #[error("Failed get output from cargo-metadata: {0:?}")]
+    GettingMetadata(#[from] cargo_metadata::Error),
+    #[error("Failed to run cargo vendor: {0:?}")]
+    LaunchingVendor(std::io::Error),
+    #[error("Failed to complete cargo vendor")]
+    RunningVendor,
+    #[error("Bad path {0:?} whilst scraping files")]
+    Scraping(PathBuf),
+}
+
+/// Uniquely describes a package on crates.io
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Package {
+    /// The name of the package
+    pub name: String,
+    /// The version number
+    pub version: String,
+}
+
+/// Extra data about a package
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct PackageMetadata {
+    /// The license it is under
+    pub license: String,
+    /// The list of authors from the package metadata
+    pub authors: Vec<String>,
+    /// A list of important files from the package, with their contents.
+    ///
+    /// This includes *COPYRIGHT*, *NOTICE*, *AUTHOR*, *LICENSE*, and *LICENCE* files, case-insensitive.
+    pub notices: BTreeMap<String, String>,
+    /// If this is true, this dep is in the Rust Standard Library
+    pub is_in_libstd: Option<bool>,
+}
+
+/// Use `cargo metadata` and `cargo vendor` to get a list of dependencies and their license data.
+///
+/// This will involve running `cargo vendor` into `${BUILD}/vendor` so we can
+/// grab the license files.
+///
+/// Any dependency with a path beginning with `root_path` is ignored, as we
+/// assume `reuse` has covered it already.
+pub fn get_metadata_and_notices(
+    cargo: &Path,
+    dest: &Path,
+    root_path: &Path,
+    manifest_paths: &[&Path],
+) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
+    let mut output = get_metadata(cargo, root_path, manifest_paths)?;
+
+    // Now do a cargo-vendor and grab everything
+    let vendor_path = dest.join("vendor");
+    println!("Vendoring deps into {}...", vendor_path.display());
+    run_cargo_vendor(cargo, &vendor_path, manifest_paths)?;
+
+    // Now for each dependency we found, go and grab any important looking files
+    for (package, metadata) in output.iter_mut() {
+        load_important_files(package, metadata, &vendor_path)?;
+    }
+
+    Ok(output)
+}
+
+/// Use `cargo metadata` to get a list of dependencies and their license data.
+///
+/// Any dependency with a path beginning with `root_path` is ignored, as we
+/// assume `reuse` has covered it already.
+pub fn get_metadata(
+    cargo: &Path,
+    root_path: &Path,
+    manifest_paths: &[&Path],
+) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
+    let mut output = BTreeMap::new();
+    // Look at the metadata for each manifest
+    for manifest_path in manifest_paths {
+        if manifest_path.file_name() != Some(OsStr::new("Cargo.toml")) {
+            panic!("cargo_manifest::get requires a path to a Cargo.toml file");
+        }
+        let metadata = cargo_metadata::MetadataCommand::new()
+            .cargo_path(cargo)
+            .env("RUSTC_BOOTSTRAP", "1")
+            .manifest_path(manifest_path)
+            .exec()?;
+        for package in metadata.packages {
+            let manifest_path = package.manifest_path.as_path();
+            if manifest_path.starts_with(root_path) {
+                // it's an in-tree dependency and reuse covers it
+                continue;
+            }
+            // otherwise it's an out-of-tree dependency
+            let package_id = Package { name: package.name, version: package.version.to_string() };
+            output.insert(
+                package_id,
+                PackageMetadata {
+                    license: package.license.unwrap_or_else(|| String::from("Unspecified")),
+                    authors: package.authors,
+                    notices: BTreeMap::new(),
+                    is_in_libstd: None,
+                },
+            );
+        }
+    }
+
+    Ok(output)
+}
+
+/// Run cargo-vendor, fetching into the given dir
+fn run_cargo_vendor(cargo: &Path, dest: &Path, manifest_paths: &[&Path]) -> Result<(), Error> {
+    let mut vendor_command = std::process::Command::new(cargo);
+    vendor_command.env("RUSTC_BOOTSTRAP", "1");
+    vendor_command.arg("vendor");
+    vendor_command.arg("--quiet");
+    vendor_command.arg("--versioned-dirs");
+    for manifest_path in manifest_paths {
+        vendor_command.arg("-s");
+        vendor_command.arg(manifest_path);
+    }
+    vendor_command.arg(dest);
+
+    let vendor_status = vendor_command.status().map_err(Error::LaunchingVendor)?;
+
+    if !vendor_status.success() {
+        return Err(Error::RunningVendor);
+    }
+
+    Ok(())
+}
+
+/// Add important files off disk into this dependency.
+///
+/// Maybe one-day Cargo.toml will contain enough information that we don't need
+/// to do this manual scraping.
+fn load_important_files(
+    package: &Package,
+    dep: &mut PackageMetadata,
+    vendor_root: &Path,
+) -> Result<(), Error> {
+    let name_version = format!("{}-{}", package.name, package.version);
+    println!("Scraping notices for {}...", name_version);
+    let dep_vendor_path = vendor_root.join(name_version);
+    for entry in std::fs::read_dir(dep_vendor_path)? {
+        let entry = entry?;
+        let metadata = entry.metadata()?;
+        let path = entry.path();
+        let Some(filename) = path.file_name() else {
+            return Err(Error::Scraping(path));
+        };
+        let lc_filename = filename.to_ascii_lowercase();
+        let lc_filename_str = lc_filename.to_string_lossy();
+        let mut keep = false;
+        for m in ["copyright", "licence", "license", "author", "notice"] {
+            if lc_filename_str.contains(m) {
+                keep = true;
+                break;
+            }
+        }
+        if keep {
+            if metadata.is_dir() {
+                for inner_entry in std::fs::read_dir(entry.path())? {
+                    let inner_entry = inner_entry?;
+                    if inner_entry.metadata()?.is_file() {
+                        let inner_filename = inner_entry.file_name();
+                        let inner_filename_str = inner_filename.to_string_lossy();
+                        let qualified_filename =
+                            format!("{}/{}", lc_filename_str, inner_filename_str);
+                        println!("Scraping {}", qualified_filename);
+                        dep.notices.insert(
+                            qualified_filename.to_string(),
+                            std::fs::read_to_string(inner_entry.path())?,
+                        );
+                    }
+                }
+            } else if metadata.is_file() {
+                let filename = filename.to_string_lossy();
+                println!("Scraping {}", filename);
+                dep.notices.insert(filename.to_string(), std::fs::read_to_string(path)?);
+            }
+        }
+    }
+    Ok(())
+}
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index dce1a558697..afa75d0d671 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -1,79 +1,70 @@
-use std::io::Write;
-use std::path::PathBuf;
+use std::collections::BTreeMap;
+use std::path::{Path, PathBuf};
 
 use anyhow::Error;
+use rinja::Template;
 
+mod cargo_metadata;
+
+#[derive(Template)]
+#[template(path = "COPYRIGHT.html")]
+struct CopyrightTemplate {
+    in_tree: Node,
+    dependencies: BTreeMap<cargo_metadata::Package, cargo_metadata::PackageMetadata>,
+}
+
+/// The entry point to the binary.
+///
+/// You should probably let `bootstrap` execute this program instead of running it directly.
+///
+/// Run `x.py run generate-copyright`
 fn main() -> Result<(), Error> {
-    let dest = env_path("DEST")?;
+    let dest_file = env_path("DEST")?;
+    let out_dir = env_path("OUT_DIR")?;
+    let cargo = env_path("CARGO")?;
     let license_metadata = env_path("LICENSE_METADATA")?;
 
-    let metadata: Metadata = serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
+    let collected_tree_metadata: Metadata =
+        serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
 
-    let mut buffer = Vec::new();
-    render_recursive(&metadata.files, &mut buffer, 0)?;
+    let root_path = std::path::absolute(".")?;
+    let workspace_paths = [
+        Path::new("./Cargo.toml"),
+        Path::new("./src/tools/cargo/Cargo.toml"),
+        Path::new("./library/Cargo.toml"),
+    ];
+    let mut collected_cargo_metadata =
+        cargo_metadata::get_metadata_and_notices(&cargo, &out_dir, &root_path, &workspace_paths)?;
 
-    std::fs::write(&dest, &buffer)?;
-
-    Ok(())
-}
+    let stdlib_set =
+        cargo_metadata::get_metadata(&cargo, &root_path, &[Path::new("./library/std/Cargo.toml")])?;
 
-fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(), Error> {
-    let prefix = std::iter::repeat("> ").take(depth + 1).collect::<String>();
-
-    match node {
-        Node::Root { children } => {
-            for child in children {
-                render_recursive(child, buffer, depth)?;
-            }
-        }
-        Node::Directory { name, children, license } => {
-            render_license(&prefix, std::iter::once(name), license.as_ref(), buffer)?;
-            if !children.is_empty() {
-                writeln!(buffer, "{prefix}")?;
-                writeln!(buffer, "{prefix}*Exceptions:*")?;
-                for child in children {
-                    writeln!(buffer, "{prefix}")?;
-                    render_recursive(child, buffer, depth + 1)?;
-                }
-            }
-        }
-        Node::Group { files, directories, license } => {
-            render_license(&prefix, directories.iter().chain(files.iter()), Some(license), buffer)?;
-        }
-        Node::File { name, license } => {
-            render_license(&prefix, std::iter::once(name), Some(license), buffer)?;
-        }
+    for (key, value) in collected_cargo_metadata.iter_mut() {
+        value.is_in_libstd = Some(stdlib_set.contains_key(key));
     }
 
-    Ok(())
-}
+    let template = CopyrightTemplate {
+        in_tree: collected_tree_metadata.files,
+        dependencies: collected_cargo_metadata,
+    };
 
-fn render_license<'a>(
-    prefix: &str,
-    names: impl Iterator<Item = &'a String>,
-    license: Option<&License>,
-    buffer: &mut Vec<u8>,
-) -> Result<(), Error> {
-    for name in names {
-        writeln!(buffer, "{prefix}**`{name}`**  ")?;
-    }
-    if let Some(license) = license {
-        writeln!(buffer, "{prefix}License: `{}`", license.spdx)?;
-        for copyright in license.copyright.iter() {
-            writeln!(buffer, "{prefix}Copyright: {copyright}")?;
-        }
-    }
+    let output = template.render()?;
+
+    std::fs::write(&dest_file, output)?;
 
     Ok(())
 }
 
+/// Describes a tree of metadata for our filesystem tree
 #[derive(serde::Deserialize)]
 struct Metadata {
     files: Node,
 }
 
-#[derive(serde::Deserialize)]
+/// Describes one node in our metadata tree
+#[derive(serde::Deserialize, rinja::Template)]
 #[serde(rename_all = "kebab-case", tag = "type")]
+#[template(path = "Node.html")]
 pub(crate) enum Node {
     Root { children: Vec<Node> },
     Directory { name: String, children: Vec<Node>, license: Option<License> },
@@ -81,12 +72,14 @@ pub(crate) enum Node {
     Group { files: Vec<String>, directories: Vec<String>, license: License },
 }
 
+/// A License has an SPDX license name and a list of copyright holders.
 #[derive(serde::Deserialize)]
 struct License {
     spdx: String,
     copyright: Vec<String>,
 }
 
+/// Grab an environment variable as a PathBuf, or fail nicely.
 fn env_path(var: &str) -> Result<PathBuf, Error> {
     if let Some(var) = std::env::var_os(var) {
         Ok(var.into())
diff --git a/src/tools/generate-copyright/templates/COPYRIGHT.html b/src/tools/generate-copyright/templates/COPYRIGHT.html
new file mode 100644
index 00000000000..ccb177a54d4
--- /dev/null
+++ b/src/tools/generate-copyright/templates/COPYRIGHT.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Copyright notices for The Rust Toolchain</title>
+</head>
+<body>
+
+<h1>Copyright notices for The Rust Toolchain</h1>
+
+<p>This file describes the copyright and licensing information for the source
+code within The Rust Project git tree, and the third-party dependencies used
+when building the Rust toolchain (including the Rust Standard Library).</p>
+
+<h2>Table of Contents</h2>
+<ul>
+    <li><a href="#in-tree-files">In-tree files</a></li>
+    <li><a href="#out-of-tree-dependencies">Out-of-tree dependencies</a></li>
+</ul>
+
+<h2 id="in-tree-files">In-tree files</h2>
+
+<p>The following licenses cover the in-tree source files that were used in this
+release:</p>
+
+{{ in_tree|safe }}
+
+<h2 id="out-of-tree-dependencies">Out-of-tree dependencies</h2>
+
+<p>The following licenses cover the out-of-tree crates that were used in this
+release:</p>
+
+{% for (key, value) in dependencies %}
+    <h3>📦 {{key.name}}-{{key.version}}</h3>
+    <p><b>URL:</b> <a href="https://crates.io/crates/{{ key.name }}/{{ key.version }}">https://crates.io/crates/{{ key.name }}/{{ key.version }}</a></p>
+    <p><b>In libstd:</b> {% if value.is_in_libstd.unwrap() %} Yes {% else %} No {% endif %}</p>
+    <p><b>Authors:</b> {{ value.authors|join(", ") }}</p>
+    <p><b>License:</b> {{ value.license }}</p>
+    {% let len = value.notices.len() %}
+    {% if len > 0 %}
+        <p><b>Notices:</b>
+        {% for (notice_name, notice_text) in value.notices %}
+            <details>
+                <summary><code>{{ notice_name }}</code></summary>
+                <pre>
+{{ notice_text }}
+                </pre>
+            </details>
+        {% endfor %}
+        </p>
+    {% endif %}
+{% endfor %}
+</body>
+</html>
\ No newline at end of file
diff --git a/src/tools/generate-copyright/templates/Node.html b/src/tools/generate-copyright/templates/Node.html
new file mode 100644
index 00000000000..a71a1bf3b73
--- /dev/null
+++ b/src/tools/generate-copyright/templates/Node.html
@@ -0,0 +1,71 @@
+{% match self %}
+
+{% when Node::Root { children } %}
+
+{% for child in children %}
+{{ child|safe }}
+{% endfor %}
+
+{% when Node::Directory { name, children, license } %}
+
+<div style="border:1px solid black; padding: 5px;">
+
+    <p>
+    <b>File/Directory:</b> <code>{{ name }}</code>
+    </p>
+
+    {% if let Some(license) = license %}
+
+    <p><b>License:</b> {{ license.spdx }}</p>
+    {% for copyright in license.copyright.iter() %}
+    <p><b>Copyright:</b> {{ copyright }}</p>
+    {% endfor %}
+
+    {% endif %}
+
+    {% if !children.is_empty() %}
+
+    <p><b>Exceptions:</b></p>
+    {% for child in children %}
+    {{ child|safe }}
+    {% endfor %}
+
+    {% endif %}
+
+</div>
+
+{% when Node::File { name, license } %}
+
+<div style="border:1px solid black; padding: 5px;">
+    <p>
+    <b>File/Directory:</b> <code>{{ name }}</code>
+    </p>
+
+    <p><b>License:</b> {{ license.spdx }}</p>
+    {% for copyright in license.copyright.iter() %}
+    <p><b>Copyright:</b> {{ copyright }}</p>
+    {% endfor %}
+</div>
+
+{% when Node::Group { files, directories, license } %}
+
+<div style="border:1px solid black; padding: 5px;">
+
+    <p>
+        <b>File/Directory:</b>
+        {% for name in files %}
+        <code>{{ name }}</code>
+        {% endfor %}
+        {% for name in directories %}
+        <code>{{ name }}</code>
+        {% endfor %}
+    </p>
+
+    <p><b>License:</b> {{ license.spdx }}</p>
+    {% for copyright in license.copyright.iter() %}
+    <p><b>Copyright:</b> {{ copyright }}</p>
+    {% endfor %}
+
+</div>
+
+{% endmatch %}
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 417ecb09b31..e4bfd9bd122 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -58,9 +58,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.82"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 
 [[package]]
 name = "autocfg"
@@ -85,15 +85,15 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "bstr"
-version = "1.9.1"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
+checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
 dependencies = [
  "memchr",
  "regex-automata",
@@ -101,10 +101,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
 name = "camino"
-version = "1.1.6"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
 dependencies = [
  "serde",
 ]
@@ -134,9 +140,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.96"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd"
+checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
 
 [[package]]
 name = "cfg-if"
@@ -258,18 +264,18 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.12"
+version = "0.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
+checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
 dependencies = [
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.19"
+version = "0.8.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
 
 [[package]]
 name = "crypto-common"
@@ -320,9 +326,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
 
 [[package]]
 name = "errno"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -356,9 +362,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -401,9 +407,9 @@ dependencies = [
 
 [[package]]
 name = "instant"
-version = "0.1.12"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
 dependencies = [
  "cfg-if",
 ]
@@ -426,9 +432,9 @@ dependencies = [
 
 [[package]]
 name = "lazy_static"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "levenshtein"
@@ -438,9 +444,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
 
 [[package]]
 name = "libc"
-version = "0.2.154"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "libffi"
@@ -463,12 +469,12 @@ dependencies = [
 
 [[package]]
 name = "libloading"
-version = "0.8.3"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
+checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
 dependencies = [
  "cfg-if",
- "windows-targets 0.52.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -483,9 +489,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "lock_api"
@@ -499,9 +505,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.21"
+version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
 [[package]]
 name = "measureme"
@@ -519,9 +525,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.7.2"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "memmap2"
@@ -534,9 +540,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.2"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
 dependencies = [
  "adler",
 ]
@@ -563,6 +569,7 @@ dependencies = [
  "smallvec",
  "tempfile",
  "ui_test",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -630,9 +637,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot"
-version = "0.12.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -648,7 +655,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets 0.52.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -715,15 +722,18 @@ checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "portable-atomic"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.17"
+version = "0.2.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
 
 [[package]]
 name = "prettydiff"
@@ -737,9 +747,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.81"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 dependencies = [
  "unicode-ident",
 ]
@@ -785,9 +795,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.1"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
+checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
 dependencies = [
  "bitflags",
 ]
@@ -805,9 +815,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.4"
+version = "1.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -817,9 +827,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.6"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -828,15 +838,15 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.3"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustc-hash"
@@ -880,9 +890,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "scopeguard"
@@ -892,27 +902,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "semver"
-version = "1.0.22"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.200"
+version = "1.0.204"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
+checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.200"
+version = "1.0.204"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
+checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -921,11 +931,12 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.116"
+version = "1.0.122"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
+checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
 dependencies = [
  "itoa",
+ "memchr",
  "ryu",
  "serde",
 ]
@@ -953,9 +964,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "syn"
-version = "2.0.60"
+version = "2.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -964,30 +975,31 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.10.1"
+version = "3.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "once_cell",
  "rustix",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.59"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
+checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.59"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
+checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1086,9 +1098,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-width"
-version = "0.1.12"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
+checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
 
 [[package]]
 name = "valuable"
@@ -1098,9 +1110,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
 [[package]]
 name = "version_check"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 
 [[package]]
 name = "wasi"
@@ -1145,7 +1157,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -1165,18 +1177,18 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.5",
- "windows_aarch64_msvc 0.52.5",
- "windows_i686_gnu 0.52.5",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.5",
- "windows_x86_64_gnu 0.52.5",
- "windows_x86_64_gnullvm 0.52.5",
- "windows_x86_64_msvc 0.52.5",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
 ]
 
 [[package]]
@@ -1187,9 +1199,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -1199,9 +1211,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -1211,15 +1223,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
 name = "windows_i686_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -1229,9 +1241,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -1241,9 +1253,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -1253,9 +1265,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -1265,9 +1277,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "yansi-term"
@@ -1277,3 +1289,24 @@ checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
 dependencies = [
  "winapi",
 ]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 976bd080867..e12f3f9012f 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -9,12 +9,12 @@ default-run = "miri"
 edition = "2021"
 
 [lib]
-test = true # we have unit tests
+test = true     # we have unit tests
 doctest = false # but no doc tests
 
 [[bin]]
 name = "miri"
-test = false # we have no unit tests
+test = false    # we have no unit tests
 doctest = false # and no doc tests
 
 [dependencies]
@@ -42,6 +42,13 @@ libc = "0.2"
 libffi = "3.2.0"
 libloading = "0.8"
 
+[target.'cfg(target_family = "windows")'.dependencies]
+windows-sys = { version = "0.52", features = [
+    "Win32_Foundation",
+    "Win32_System_IO",
+    "Win32_Storage_FileSystem",
+] }
+
 [dev-dependencies]
 colored = "2"
 ui_test = "0.21.1"
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index b1be596c006..499d0fe2f1c 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -398,6 +398,8 @@ to Miri failing to detect cases of undefined behavior in a program.
   application instead of raising an error within the context of Miri (and halting
   execution). Note that code might not expect these operations to ever panic, so
   this flag can lead to strange (mis)behavior.
+* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking
+  recurse below references.
 * `-Zmiri-retag-fields[=<all|none|scalar>]` controls when Stacked Borrows retagging recurses into
   fields. `all` means it always recurses (the default, and equivalent to `-Zmiri-retag-fields`
   without an explicit value), `none` means it never recurses, `scalar` means it only recurses for
@@ -474,6 +476,19 @@ Miri provides some `extern` functions that programs can import to access
 Miri-specific functionality. They are declared in
 [/tests/utils/miri\_extern.rs](/tests/utils/miri_extern.rs).
 
+## Entry point for no-std binaries
+
+Binaries that do not use the standard library are expected to declare a function like this so that
+Miri knows where it is supposed to start execution:
+
+```rust
+#[cfg(miri)]
+#[no_mangle]
+fn miri_start(argc: isize, argv: *const *const u8) -> isize {
+    // Call the actual start function that your project implements, based on your target's conventions.
+}
+```
+
 ## Contributing and getting help
 
 If you want to contribute to Miri, great!  Please check out our
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index 8bd8f103053..7369a3fbf09 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -4,21 +4,21 @@ version = 3
 
 [[package]]
 name = "anyhow"
-version = "1.0.82"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 
 [[package]]
 name = "bitflags"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "camino"
-version = "1.1.6"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
 dependencies = [
  "serde",
 ]
@@ -88,9 +88,9 @@ dependencies = [
 
 [[package]]
 name = "errno"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -104,9 +104,9 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
 
 [[package]]
 name = "getrandom"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -121,9 +121,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "libc"
-version = "0.2.154"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "libredox"
@@ -137,9 +137,21 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
 name = "option-ext"
@@ -149,9 +161,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.81"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 dependencies = [
  "unicode-ident",
 ]
@@ -178,9 +190,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.2"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa3ca63cc537c1cb69e4c2c0afc5fda2ccd36ac84c97d5a4ae05e69b1c834afb"
+checksum = "2471f8f296262437d7e848e527b4210b44a96e53a3b4435b890227ce3e6da106"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -218,9 +230,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "same-file"
@@ -233,27 +245,27 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.22"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.200"
+version = "1.0.204"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
+checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.200"
+version = "1.0.204"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
+checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -262,20 +274,21 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.116"
+version = "1.0.122"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
+checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
 dependencies = [
  "itoa",
+ "memchr",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.60"
+version = "2.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -284,30 +297,31 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.10.1"
+version = "3.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "once_cell",
  "rustix",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.59"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
+checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.59"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
+checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -338,11 +352,11 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -360,7 +374,16 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.5",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -380,18 +403,18 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.5",
- "windows_aarch64_msvc 0.52.5",
- "windows_i686_gnu 0.52.5",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.5",
- "windows_x86_64_gnu 0.52.5",
- "windows_x86_64_gnullvm 0.52.5",
- "windows_x86_64_msvc 0.52.5",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
 ]
 
 [[package]]
@@ -402,9 +425,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -414,9 +437,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -426,15 +449,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
 name = "windows_i686_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -444,9 +467,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -456,9 +479,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -468,9 +491,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -480,6 +503,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index 6acdbc46f64..477c60db162 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -18,7 +18,7 @@ directories = "5"
 rustc_version = "0.4"
 serde_json = "1.0.40"
 cargo_metadata = "0.18.0"
-rustc-build-sysroot = "0.5.2"
+rustc-build-sysroot = "0.5.3"
 
 # Enable some feature flags that dev-dependencies need but dependencies
 # do not.  This makes `./miri install` after `./miri build` faster.
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 62a3ab2c34c..fc205040baf 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -355,7 +355,10 @@ impl Command {
         let head = cmd!(sh, "git rev-parse HEAD").read()?;
         let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
         if head != fetch_head {
-            bail!("Josh created a non-roundtrip push! Do NOT merge this into rustc!");
+            bail!(
+                "Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\
+                Expected {head}, got {fetch_head}."
+            );
         }
         println!(
             "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 58ec4e10856..b74f9759ebe 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-a526d7ce45fd2284e0e7c7556ccba2425b9d25e5
+29e924841f06bb181d87494eba2783761bc1ddec
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 25b154a8206..e13e54c3309 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -14,11 +14,14 @@ extern crate tracing;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_hir;
+extern crate rustc_hir_analysis;
 extern crate rustc_interface;
 extern crate rustc_log;
 extern crate rustc_metadata;
 extern crate rustc_middle;
 extern crate rustc_session;
+extern crate rustc_span;
+extern crate rustc_target;
 
 use std::env::{self, VarError};
 use std::num::NonZero;
@@ -29,7 +32,9 @@ use tracing::debug;
 
 use rustc_data_structures::sync::Lrc;
 use rustc_driver::Compilation;
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_hir::{self as hir, Node};
+use rustc_hir_analysis::check::check_function_signature;
 use rustc_interface::interface::Config;
 use rustc_middle::{
     middle::{
@@ -37,14 +42,17 @@ use rustc_middle::{
         exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel},
     },
     query::LocalCrate,
-    ty::TyCtxt,
+    traits::{ObligationCause, ObligationCauseCode},
+    ty::{self, Ty, TyCtxt},
     util::Providers,
 };
-use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
+use rustc_session::config::{CrateType, EntryFnType, ErrorOutputType, OptLevel};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
+use rustc_span::def_id::DefId;
+use rustc_target::spec::abi::Abi;
 
-use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields};
+use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields, ValidationMode};
 
 struct MiriCompilerCalls {
     miri_config: miri::MiriConfig,
@@ -82,11 +90,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                 tcx.dcx().fatal("miri only makes sense on bin crates");
             }
 
-            let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) {
-                entry_def
-            } else {
-                tcx.dcx().fatal("miri can only run programs that have a main function");
-            };
+            let (entry_def_id, entry_type) = entry_fn(tcx);
             let mut config = self.miri_config.clone();
 
             // Add filename to `miri` arguments.
@@ -351,6 +355,56 @@ fn jemalloc_magic() {
     }
 }
 
+fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) {
+    if let Some(entry_def) = tcx.entry_fn(()) {
+        return entry_def;
+    }
+    // Look for a symbol in the local crate named `miri_start`, and treat that as the entry point.
+    let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
+        if sym.symbol_name_for_local_instance(tcx).name == "miri_start" { Some(sym) } else { None }
+    });
+    if let Some(ExportedSymbol::NonGeneric(id)) = sym {
+        let start_def_id = id.expect_local();
+        let start_span = tcx.def_span(start_def_id);
+
+        let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+            [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
+            tcx.types.isize,
+            false,
+            hir::Safety::Safe,
+            Abi::Rust,
+        ));
+
+        let correct_func_sig = check_function_signature(
+            tcx,
+            ObligationCause::new(start_span, start_def_id, ObligationCauseCode::Misc),
+            *id,
+            expected_sig,
+        )
+        .is_ok();
+
+        if correct_func_sig {
+            (*id, EntryFnType::Start)
+        } else {
+            tcx.dcx().fatal(
+                "`miri_start` must have the following signature:\n\
+                        fn miri_start(argc: isize, argv: *const *const u8) -> isize",
+            );
+        }
+    } else {
+        tcx.dcx().fatal(
+            "Miri can only run programs that have a main function.\n\
+            Alternatively, you can export a `miri_start` function:\n\
+            \n\
+            #[cfg(miri)]\n\
+            #[no_mangle]\n\
+            fn miri_start(argc: isize, argv: *const *const u8) -> isize {\
+            \n    // Call the actual start function that your project implements, based on your target's conventions.\n\
+            }"
+        );
+    }
+}
+
 fn main() {
     #[cfg(any(target_os = "linux", target_os = "macos"))]
     jemalloc_magic();
@@ -421,7 +475,9 @@ fn main() {
         } else if arg == "--" {
             after_dashdash = true;
         } else if arg == "-Zmiri-disable-validation" {
-            miri_config.validate = false;
+            miri_config.validation = ValidationMode::No;
+        } else if arg == "-Zmiri-recursive-validation" {
+            miri_config.validation = ValidationMode::Deep;
         } else if arg == "-Zmiri-disable-stacked-borrows" {
             miri_config.borrow_tracker = None;
         } else if arg == "-Zmiri-tree-borrows" {
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 3f9c991df6a..fc2b3f9c6ea 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -673,7 +673,8 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
             // attempt to use it for a non-zero-sized access.
             // Dangling slices are a common case here; it's valid to get their length but with raw
             // pointer tagging for example all calls to get_unchecked on them are invalid.
-            if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr(), 0) {
+            if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr(), 0)
+            {
                 log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
                 // Still give it the new provenance, it got retagged after all.
                 return Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index a53dd7eac1e..f72591f0c4b 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -256,7 +256,7 @@ pub struct Thread<'tcx> {
     /// which then forwards it to 'Resume'. However this argument is implicit in MIR,
     /// so we have to store it out-of-band. When there are multiple active unwinds,
     /// the innermost one is always caught first, so we can store them as a stack.
-    pub(crate) panic_payloads: Vec<Scalar>,
+    pub(crate) panic_payloads: Vec<ImmTy<'tcx>>,
 
     /// Last OS error location in memory. It is a 32-bit integer.
     pub(crate) last_error: Option<MPlaceTy<'tcx>>,
@@ -377,10 +377,6 @@ impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> {
             return_place,
             locals,
             extra,
-            body: _,
-            instance: _,
-            return_to_block: _,
-            loc: _,
             // There are some private fields we cannot access; they contain no tags.
             ..
         } = self;
@@ -952,7 +948,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             instance,
             start_abi,
-            &[*func_arg],
+            &[func_arg],
             Some(&ret_place),
             StackPopCleanup::Root { cleanup: true },
         )?;
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 2184a4426c8..d781188cd0c 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -68,7 +68,7 @@ pub enum IsolatedOp {
     Allow,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum BacktraceStyle {
     /// Prints a terser backtrace which ideally only contains relevant information.
     Short,
@@ -78,6 +78,16 @@ pub enum BacktraceStyle {
     Off,
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ValidationMode {
+    /// Do not perform any kind of validation.
+    No,
+    /// Validate the interior of the value, but not things behind references.
+    Shallow,
+    /// Fully recursively validate references.
+    Deep,
+}
+
 /// Configuration needed to spawn a Miri instance.
 #[derive(Clone)]
 pub struct MiriConfig {
@@ -85,7 +95,7 @@ pub struct MiriConfig {
     /// (This is still subject to isolation as well as `forwarded_env_vars`.)
     pub env: Vec<(OsString, OsString)>,
     /// Determine if validity checking is enabled.
-    pub validate: bool,
+    pub validation: ValidationMode,
     /// Determines if Stacked Borrows or Tree Borrows is enabled.
     pub borrow_tracker: Option<BorrowTrackerMethod>,
     /// Whether `core::ptr::Unique` receives special treatment.
@@ -162,7 +172,7 @@ impl Default for MiriConfig {
     fn default() -> MiriConfig {
         MiriConfig {
             env: vec![],
-            validate: true,
+            validation: ValidationMode::Shallow,
             borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows),
             unique_is_unique: false,
             check_alignment: AlignmentCheck::Int,
@@ -297,7 +307,8 @@ pub fn create_ecx<'tcx>(
     // First argument is constructed later, because it's skipped if the entry function uses #[start].
 
     // Second argument (argc): length of `config.args`.
-    let argc = Scalar::from_target_usize(u64::try_from(config.args.len()).unwrap(), &ecx);
+    let argc =
+        ImmTy::from_int(i64::try_from(config.args.len()).unwrap(), ecx.machine.layouts.isize);
     // Third argument (`argv`): created from `config.args`.
     let argv = {
         // Put each argument in memory, collect pointers.
@@ -324,13 +335,11 @@ pub fn create_ecx<'tcx>(
             ecx.write_immediate(arg, &place)?;
         }
         ecx.mark_immutable(&argvs_place);
-        // A pointer to that place is the 3rd argument for main.
-        let argv = argvs_place.to_ref(&ecx);
         // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
         {
             let argc_place =
                 ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
-            ecx.write_scalar(argc, &argc_place)?;
+            ecx.write_immediate(*argc, &argc_place)?;
             ecx.mark_immutable(&argc_place);
             ecx.machine.argc = Some(argc_place.ptr());
 
@@ -338,7 +347,7 @@ pub fn create_ecx<'tcx>(
                 ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?,
                 MiriMemoryKind::Machine.into(),
             )?;
-            ecx.write_immediate(argv, &argv_place)?;
+            ecx.write_pointer(argvs_place.ptr(), &argv_place)?;
             ecx.mark_immutable(&argv_place);
             ecx.machine.argv = Some(argv_place.ptr());
         }
@@ -359,7 +368,7 @@ pub fn create_ecx<'tcx>(
             }
             ecx.mark_immutable(&cmd_place);
         }
-        argv
+        ecx.mplace_to_ref(&argvs_place)?
     };
 
     // Return place (in static memory so that it does not count as leak).
@@ -395,10 +404,14 @@ pub fn create_ecx<'tcx>(
                 start_instance,
                 Abi::Rust,
                 &[
-                    Scalar::from_pointer(main_ptr, &ecx).into(),
-                    argc.into(),
+                    ImmTy::from_scalar(
+                        Scalar::from_pointer(main_ptr, &ecx),
+                        // FIXME use a proper fn ptr type
+                        ecx.machine.layouts.const_raw_ptr,
+                    ),
+                    argc,
                     argv,
-                    Scalar::from_u8(sigpipe).into(),
+                    ImmTy::from_uint(sigpipe, ecx.machine.layouts.u8),
                 ],
                 Some(&ret_place),
                 StackPopCleanup::Root { cleanup: true },
@@ -408,7 +421,7 @@ pub fn create_ecx<'tcx>(
             ecx.call_function(
                 entry_instance,
                 Abi::Rust,
-                &[argc.into(), argv],
+                &[argc, argv],
                 Some(&ret_place),
                 StackPopCleanup::Root { cleanup: true },
             )?;
@@ -450,6 +463,7 @@ pub fn eval_entry<'tcx>(
     let res = match res {
         Err(res) => res,
         // `Ok` can never happen
+        #[cfg(bootstrap)]
         Ok(never) => match never {},
     };
 
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 8bc8188f053..1bdf9f06dcd 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -12,13 +12,14 @@ use rustc_apfloat::Float;
 use rustc_hir::{
     def::{DefKind, Namespace},
     def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE},
+    Safety,
 };
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::mir;
-use rustc_middle::ty::layout::MaybeResult;
+use rustc_middle::ty::layout::{FnAbiOf, MaybeResult};
 use rustc_middle::ty::{
     self,
     layout::{LayoutOf, TyAndLayout},
@@ -492,48 +493,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         f: ty::Instance<'tcx>,
         caller_abi: Abi,
-        args: &[Immediate<Provenance>],
+        args: &[ImmTy<'tcx>],
         dest: Option<&MPlaceTy<'tcx>>,
         stack_pop: StackPopCleanup,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
-        let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
-        if callee_abi != caller_abi {
-            throw_ub_format!(
-                "calling a function with ABI {} using caller ABI {}",
-                callee_abi.name(),
-                caller_abi.name()
-            )
-        }
 
-        // Push frame.
+        // Get MIR.
         let mir = this.load_mir(f.def, None)?;
         let dest = match dest {
             Some(dest) => dest.clone(),
             None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?),
         };
-        this.push_stack_frame(f, mir, &dest, stack_pop)?;
-
-        // Initialize arguments.
-        let mut callee_args = this.frame().body.args_iter();
-        for arg in args {
-            let local = callee_args
-                .next()
-                .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?;
-            // Make the local live, and insert the initial value.
-            this.storage_live(local)?;
-            let callee_arg = this.local_to_place(local)?;
-            this.write_immediate(*arg, &callee_arg)?;
-        }
-        if callee_args.next().is_some() {
-            throw_ub_format!("callee has more arguments than expected");
-        }
-
-        // Initialize remaining locals.
-        this.storage_live_for_always_live_locals()?;
 
-        Ok(())
+        // Construct a function pointer type representing the caller perspective.
+        let sig = this.tcx.mk_fn_sig(
+            args.iter().map(|a| a.layout.ty),
+            dest.layout.ty,
+            /*c_variadic*/ false,
+            Safety::Safe,
+            caller_abi,
+        );
+        let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?;
+
+        this.init_stack_frame(
+            f,
+            mir,
+            caller_fn_abi,
+            &args.iter().map(|a| FnArg::Copy(a.clone().into())).collect::<Vec<_>>(),
+            /*with_caller_location*/ false,
+            &dest,
+            stack_pop,
+        )
     }
 
     /// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter
@@ -1114,12 +1105,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Make an attempt to get at the instance of the function this is inlined from.
         let instance: Option<_> = try {
             let scope = frame.current_source_info()?.scope;
-            let inlined_parent = frame.body.source_scopes[scope].inlined_parent_scope?;
-            let source = &frame.body.source_scopes[inlined_parent];
+            let inlined_parent = frame.body().source_scopes[scope].inlined_parent_scope?;
+            let source = &frame.body().source_scopes[inlined_parent];
             source.inlined.expect("inlined_parent_scope points to scope without inline info").0
         };
         // Fall back to the instance of the function itself.
-        let instance = instance.unwrap_or(frame.instance);
+        let instance = instance.unwrap_or(frame.instance());
         // Now check the crate it is in. We could try to be clever here and e.g. check if this is
         // the same crate as `start_fn`, but that would not work for running std tests in Miri, so
         // we'd need some more hacks anyway. So we just check the name of the crate. If someone
@@ -1359,9 +1350,9 @@ impl<'tcx> MiriMachine<'tcx> {
 
     /// This is the source of truth for the `is_user_relevant` flag in our `FrameExtra`.
     pub fn is_user_relevant(&self, frame: &Frame<'tcx, Provenance>) -> bool {
-        let def_id = frame.instance.def_id();
+        let def_id = frame.instance().def_id();
         (def_id.is_local() || self.local_crates.contains(&def_id.krate))
-            && !frame.instance.def.requires_caller_location(self.tcx)
+            && !frame.instance().def.requires_caller_location(self.tcx)
     }
 }
 
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 9cd776c9371..18b22827bdb 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // See if the core engine can handle this intrinsic.
-        if this.emulate_intrinsic(instance, args, dest, ret)? {
+        if this.eval_intrinsic(instance, args, dest, ret)? {
             return Ok(None);
         }
         let intrinsic_name = this.tcx.item_name(instance.def_id());
@@ -153,7 +153,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Would not be considered UB, or the other way around (`is_val_statically_known(0)`).
             "is_val_statically_known" => {
                 let [arg] = check_arg_count(args)?;
-                this.validate_operand(arg)?;
+                this.validate_operand(arg, /*recursive*/ false)?;
                 let branch: bool = this.machine.rng.get_mut().gen();
                 this.write_scalar(Scalar::from_bool(branch), dest)?;
             }
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 24909f21eb2..2b3ae6df5de 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -142,6 +142,7 @@ pub use crate::diagnostics::{
 };
 pub use crate::eval::{
     create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith,
+    ValidationMode,
 };
 pub use crate::helpers::{AccessKind, EvalContextExt as _};
 pub use crate::machine::{
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 5f4aa9d2f5d..94598e7d2e3 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -187,7 +187,11 @@ impl fmt::Display for MiriMemoryKind {
 pub type MemoryKind = interpret::MemoryKind<MiriMemoryKind>;
 
 /// Pointer provenance.
-#[derive(Clone, Copy)]
+// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking
+// *might* be recursive and then it has to track which places have already been visited.
+// These implementations are a bit questionable, and it means we may check the same place multiple
+// times with different provenance, but that is in general not wrong.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum Provenance {
     /// For pointers with concrete provenance. we exactly know which allocation they are attached to
     /// and what their borrow tag is.
@@ -215,24 +219,6 @@ pub enum Provenance {
     Wildcard,
 }
 
-// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking
-// *might* be recursive and then it has to track which places have already been visited.
-// However, comparing provenance is meaningless, since `Wildcard` might be any provenance -- and of
-// course we don't actually do recursive checking.
-// We could change `RefTracking` to strip provenance for its `seen` set but that type is generic so that is quite annoying.
-// Instead owe add the required instances but make them panic.
-impl PartialEq for Provenance {
-    fn eq(&self, _other: &Self) -> bool {
-        panic!("Provenance must not be compared")
-    }
-}
-impl Eq for Provenance {}
-impl std::hash::Hash for Provenance {
-    fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {
-        panic!("Provenance must not be hashed")
-    }
-}
-
 /// The "extra" information a pointer has over a regular AllocId.
 #[derive(Copy, Clone, PartialEq)]
 pub enum ProvenanceExtra {
@@ -460,7 +446,7 @@ pub struct MiriMachine<'tcx> {
     pub(crate) isolated_op: IsolatedOp,
 
     /// Whether to enforce the validity invariant.
-    pub(crate) validate: bool,
+    pub(crate) validation: ValidationMode,
 
     /// The table of file descriptors.
     pub(crate) fds: shims::FdTable,
@@ -659,7 +645,7 @@ impl<'tcx> MiriMachine<'tcx> {
             cmd_line: None,
             tls: TlsData::default(),
             isolated_op: config.isolated_op,
-            validate: config.validate,
+            validation: config.validation,
             fds: shims::FdTable::init(config.mute_stdout_stderr),
             dirs: Default::default(),
             layouts,
@@ -801,7 +787,7 @@ impl VisitProvenance for MiriMachine<'_> {
             fds,
             tcx: _,
             isolated_op: _,
-            validate: _,
+            validation: _,
             clock: _,
             layouts: _,
             static_roots: _,
@@ -943,7 +929,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
 
     #[inline(always)]
     fn enforce_validity(ecx: &MiriInterpCx<'tcx>, _layout: TyAndLayout<'tcx>) -> bool {
-        ecx.machine.validate
+        ecx.machine.validation != ValidationMode::No
+    }
+    #[inline(always)]
+    fn enforce_validity_recursively(
+        ecx: &InterpCx<'tcx, Self>,
+        _layout: TyAndLayout<'tcx>,
+    ) -> bool {
+        ecx.machine.validation == ValidationMode::Deep
     }
 
     #[inline(always)]
@@ -1359,7 +1352,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     ) -> InterpResult<'tcx, Frame<'tcx, Provenance, FrameExtra<'tcx>>> {
         // Start recording our event before doing anything else
         let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() {
-            let fn_name = frame.instance.to_string();
+            let fn_name = frame.instance().to_string();
             let entry = ecx.machine.string_cache.entry(fn_name.clone());
             let name = entry.or_insert_with(|| profiler.alloc_string(&*fn_name));
 
@@ -1450,7 +1443,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         // tracing-tree can autoamtically annotate scope changes, but it gets very confused by our
         // concurrency and what it prints is just plain wrong. So we print our own information
         // instead. (Cc https://github.com/rust-lang/miri/issues/2266)
-        info!("Leaving {}", ecx.frame().instance);
+        info!("Leaving {}", ecx.frame().instance());
         Ok(())
     }
 
@@ -1480,7 +1473,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         // Needs to be done after dropping frame to show up on the right nesting level.
         // (Cc https://github.com/rust-lang/miri/issues/2266)
         if !ecx.active_thread_stack().is_empty() {
-            info!("Continuing in {}", ecx.frame().instance);
+            info!("Continuing in {}", ecx.frame().instance());
         }
         res
     }
@@ -1493,7 +1486,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else {
             panic!("after_local_allocated should only be called on fresh allocations");
         };
-        let local_decl = &ecx.frame().body.local_decls[local];
+        let local_decl = &ecx.frame().body().local_decls[local];
         let span = local_decl.source_info.span;
         ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None));
         Ok(())
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 42babb4c78d..9bb6777a9b0 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -46,8 +46,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let mut data = Vec::new();
         for frame in this.active_thread_stack().iter().rev() {
             // Match behavior of debuginfo (`FunctionCx::adjusted_span_and_dbg_scope`).
-            let span = hygiene::walk_chain_collapsed(frame.current_span(), frame.body.span);
-            data.push((frame.instance, span.lo()));
+            let span = hygiene::walk_chain_collapsed(frame.current_span(), frame.body().span);
+            data.push((frame.instance(), span.lo()));
         }
 
         let ptrs: Vec<_> = data
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 306dce5edcd..ab705ddccab 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -25,7 +25,7 @@ pub struct CatchUnwindData<'tcx> {
     /// The `catch_fn` callback to call in case of a panic.
     catch_fn: Pointer,
     /// The `data` argument for that callback.
-    data: Scalar,
+    data: ImmTy<'tcx>,
     /// The return place from the original call to `try`.
     dest: MPlaceTy<'tcx>,
     /// The return block from the original call to `try`.
@@ -48,9 +48,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        trace!("miri_start_unwind: {:?}", this.frame().instance);
+        trace!("miri_start_unwind: {:?}", this.frame().instance());
 
-        let payload = this.read_scalar(payload)?;
+        let payload = this.read_immediate(payload)?;
         let thread = this.active_thread_mut();
         thread.panic_payloads.push(payload);
 
@@ -80,7 +80,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Get all the arguments.
         let [try_fn, data, catch_fn] = check_arg_count(args)?;
         let try_fn = this.read_pointer(try_fn)?;
-        let data = this.read_scalar(data)?;
+        let data = this.read_immediate(data)?;
         let catch_fn = this.read_pointer(catch_fn)?;
 
         // Now we make a function call, and pass `data` as first and only argument.
@@ -89,7 +89,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             f_instance,
             Abi::Rust,
-            &[data.into()],
+            &[data.clone()],
             None,
             // Directly return to caller.
             StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Continue },
@@ -124,7 +124,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and we are unwinding, so we should catch that.
             trace!(
                 "unwinding: found catch_panic frame during unwinding: {:?}",
-                this.frame().instance
+                this.frame().instance()
             );
 
             // We set the return value of `try` to 1, since there was a panic.
@@ -140,7 +140,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.call_function(
                 f_instance,
                 Abi::Rust,
-                &[catch_unwind.data.into(), payload.into()],
+                &[catch_unwind.data, payload],
                 None,
                 // Directly return to caller of `try`.
                 StackPopCleanup::Goto {
@@ -169,7 +169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             panic,
             Abi::Rust,
-            &[msg.to_ref(this)],
+            &[this.mplace_to_ref(&msg)?],
             None,
             StackPopCleanup::Goto { ret: None, unwind },
         )
@@ -188,7 +188,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             panic,
             Abi::Rust,
-            &[msg.to_ref(this)],
+            &[this.mplace_to_ref(&msg)?],
             None,
             StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
         )
@@ -207,9 +207,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Forward to `panic_bounds_check` lang item.
 
                 // First arg: index.
-                let index = this.read_scalar(&this.eval_operand(index, None)?)?;
+                let index = this.read_immediate(&this.eval_operand(index, None)?)?;
                 // Second arg: len.
-                let len = this.read_scalar(&this.eval_operand(len, None)?)?;
+                let len = this.read_immediate(&this.eval_operand(len, None)?)?;
 
                 // Call the lang item.
                 let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap();
@@ -217,7 +217,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.call_function(
                     panic_bounds_check,
                     Abi::Rust,
-                    &[index.into(), len.into()],
+                    &[index, len],
                     None,
                     StackPopCleanup::Goto { ret: None, unwind },
                 )?;
@@ -226,9 +226,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Forward to `panic_misaligned_pointer_dereference` lang item.
 
                 // First arg: required.
-                let required = this.read_scalar(&this.eval_operand(required, None)?)?;
+                let required = this.read_immediate(&this.eval_operand(required, None)?)?;
                 // Second arg: found.
-                let found = this.read_scalar(&this.eval_operand(found, None)?)?;
+                let found = this.read_immediate(&this.eval_operand(found, None)?)?;
 
                 // Call the lang item.
                 let panic_misaligned_pointer_dereference =
@@ -238,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.call_function(
                     panic_misaligned_pointer_dereference,
                     Abi::Rust,
-                    &[required.into(), found.into()],
+                    &[required, found],
                     None,
                     StackPopCleanup::Goto { ret: None, unwind },
                 )?;
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index e8f906d37e8..ebec1a70c5c 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -93,7 +93,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(Scalar::from_i32(0))
     }
 
-    fn gettimeofday(&mut self, tv_op: &OpTy<'tcx>, tz_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn gettimeofday(
+        &mut self,
+        tv_op: &OpTy<'tcx>,
+        tz_op: &OpTy<'tcx>,
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         this.assert_target_os_is_unix("gettimeofday");
@@ -106,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if !this.ptr_is_null(tz)? {
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let duration = system_time_to_duration(&SystemTime::now())?;
@@ -115,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &tv)?;
 
-        Ok(0)
+        Ok(Scalar::from_i32(0))
     }
 
     // The localtime() function shall convert the time in seconds since the Epoch pointed to by
@@ -308,7 +312,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         req_op: &OpTy<'tcx>,
         _rem: &OpTy<'tcx>, // Signal handlers are not supported, so rem will never be written to.
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         this.assert_target_os_is_unix("nanosleep");
@@ -320,7 +324,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             None => {
                 let einval = this.eval_libc("EINVAL");
                 this.set_last_error(einval)?;
-                return Ok(-1);
+                return Ok(Scalar::from_i32(-1));
             }
         };
 
@@ -333,7 +337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 @timeout = |_this| { Ok(()) }
             ),
         );
-        Ok(0)
+        Ok(Scalar::from_i32(0))
     }
 
     #[allow(non_snake_case)]
diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs
index 87074468789..52d83cd7299 100644
--- a/src/tools/miri/src/shims/tls.rs
+++ b/src/tools/miri/src/shims/tls.rs
@@ -315,6 +315,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // FIXME: Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits
         // but std treats both the same.
         let reason = this.eval_windows("c", "DLL_THREAD_DETACH");
+        let null_ptr =
+            ImmTy::from_scalar(Scalar::null_ptr(this), this.machine.layouts.const_raw_ptr);
 
         // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`.
         // FIXME: `h` should be a handle to the current module and what `pv` should be is unknown
@@ -322,7 +324,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             thread_callback,
             Abi::System { unwind: false },
-            &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()],
+            &[null_ptr.clone(), ImmTy::from_scalar(reason, this.machine.layouts.u32), null_ptr],
             None,
             StackPopCleanup::Root { cleanup: true },
         )?;
@@ -343,7 +345,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.call_function(
                 instance,
                 Abi::C { unwind: false },
-                &[data.into()],
+                &[ImmTy::from_scalar(data, this.machine.layouts.mut_raw_ptr)],
                 None,
                 StackPopCleanup::Root { cleanup: true },
             )?;
@@ -380,7 +382,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.call_function(
                 instance,
                 Abi::C { unwind: false },
-                &[ptr.into()],
+                &[ImmTy::from_scalar(ptr, this.machine.layouts.mut_raw_ptr)],
                 None,
                 StackPopCleanup::Root { cleanup: true },
             )?;
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 08b9b4e8fa3..54bf3a3ae82 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -81,8 +81,10 @@ impl<'tcx> UnixEnvVars<'tcx> {
             return Ok(None);
         };
         // The offset is used to strip the "{name}=" part of the string.
-        let var_ptr = var_ptr
-            .wrapping_offset(Size::from_bytes(u64::try_from(name.len()).unwrap().strict_add(1)), ecx);
+        let var_ptr = var_ptr.wrapping_offset(
+            Size::from_bytes(u64::try_from(name.len()).unwrap().strict_add(1)),
+            ecx,
+        );
         Ok(Some(var_ptr))
     }
 
@@ -148,7 +150,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(var_ptr.unwrap_or_else(Pointer::null))
     }
 
-    fn setenv(&mut self, name_op: &OpTy<'tcx>, value_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn setenv(
+        &mut self,
+        name_op: &OpTy<'tcx>,
+        value_op: &OpTy<'tcx>,
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("setenv");
 
@@ -169,16 +175,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
             }
             this.update_environ()?;
-            Ok(0) // return zero on success
+            Ok(Scalar::from_i32(0)) // return zero on success
         } else {
             // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            Ok(-1)
+            Ok(Scalar::from_i32(-1))
         }
     }
 
-    fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("unsetenv");
 
@@ -195,12 +201,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
             }
             this.update_environ()?;
-            Ok(0)
+            Ok(Scalar::from_i32(0))
         } else {
             // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            Ok(-1)
+            Ok(Scalar::from_i32(-1))
         }
     }
 
@@ -232,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(Pointer::null())
     }
 
-    fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("chdir");
 
@@ -242,16 +248,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`chdir`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
 
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
-        match env::set_current_dir(path) {
-            Ok(()) => Ok(0),
-            Err(e) => {
-                this.set_last_error_from_io_error(e)?;
-                Ok(-1)
-            }
-        }
+        let result = env::set_current_dir(path).map(|()| 0);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     /// Updates the `environ` static.
@@ -270,18 +271,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn getpid(&mut self) -> InterpResult<'tcx, i32> {
+    fn getpid(&mut self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("getpid");
 
         // The reason we need to do this wacky of a conversion is because
         // `libc::getpid` returns an i32, however, `std::process::id()` return an u32.
         // So we un-do the conversion that stdlib does and turn it back into an i32.
-        #[allow(clippy::cast_possible_wrap)]
-        Ok(this.get_pid() as i32)
+        // In `Scalar` representation, these are the same, so we don't need to anything else.
+        Ok(Scalar::from_u32(this.get_pid()))
     }
 
-    fn linux_gettid(&mut self) -> InterpResult<'tcx, i32> {
+    fn linux_gettid(&mut self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_ref();
         this.assert_target_os("linux", "gettid");
 
@@ -290,7 +291,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Compute a TID for this thread, ensuring that the main thread has PID == TID.
         let tid = this.get_pid().strict_add(index);
 
-        #[allow(clippy::cast_possible_wrap)]
-        Ok(tid as i32)
+        Ok(Scalar::from_u32(tid))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 0fffecd99d5..1b25ef05769 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -12,6 +12,13 @@ use rustc_target::abi::Size;
 use crate::shims::unix::*;
 use crate::*;
 
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub(crate) enum FlockOp {
+    SharedLock { nonblocking: bool },
+    ExclusiveLock { nonblocking: bool },
+    Unlock,
+}
+
 /// Represents an open file descriptor.
 pub trait FileDescription: std::fmt::Debug + Any {
     fn name(&self) -> &'static str;
@@ -77,6 +84,14 @@ pub trait FileDescription: std::fmt::Debug + Any {
         throw_unsup_format!("cannot close {}", self.name());
     }
 
+    fn flock<'tcx>(
+        &self,
+        _communicate_allowed: bool,
+        _op: FlockOp,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        throw_unsup_format!("cannot flock {}", self.name());
+    }
+
     fn is_tty(&self, _communicate_allowed: bool) -> bool {
         // Most FDs are not tty's and the consequence of a wrong `false` are minor,
         // so we use a default impl here.
@@ -189,9 +204,13 @@ impl FileDescription for NullOutput {
 }
 
 #[derive(Clone, Debug)]
-pub struct FileDescriptor(Rc<RefCell<Box<dyn FileDescription>>>);
+pub struct FileDescriptionRef(Rc<RefCell<Box<dyn FileDescription>>>);
+
+impl FileDescriptionRef {
+    fn new(fd: impl FileDescription) -> Self {
+        FileDescriptionRef(Rc::new(RefCell::new(Box::new(fd))))
+    }
 
-impl FileDescriptor {
     pub fn borrow(&self) -> Ref<'_, dyn FileDescription> {
         Ref::map(self.0.borrow(), |fd| fd.as_ref())
     }
@@ -213,7 +232,7 @@ impl FileDescriptor {
 /// The file descriptor table
 #[derive(Debug)]
 pub struct FdTable {
-    pub fds: BTreeMap<i32, FileDescriptor>,
+    fds: BTreeMap<i32, FileDescriptionRef>,
 }
 
 impl VisitProvenance for FdTable {
@@ -228,25 +247,25 @@ impl FdTable {
     }
     pub(crate) fn init(mute_stdout_stderr: bool) -> FdTable {
         let mut fds = FdTable::new();
-        fds.insert_fd(io::stdin());
+        fds.insert_new(io::stdin());
         if mute_stdout_stderr {
-            assert_eq!(fds.insert_fd(NullOutput), 1);
-            assert_eq!(fds.insert_fd(NullOutput), 2);
+            assert_eq!(fds.insert_new(NullOutput), 1);
+            assert_eq!(fds.insert_new(NullOutput), 2);
         } else {
-            assert_eq!(fds.insert_fd(io::stdout()), 1);
-            assert_eq!(fds.insert_fd(io::stderr()), 2);
+            assert_eq!(fds.insert_new(io::stdout()), 1);
+            assert_eq!(fds.insert_new(io::stderr()), 2);
         }
         fds
     }
 
-    /// Insert a file descriptor to the FdTable.
-    pub fn insert_fd<T: FileDescription>(&mut self, fd: T) -> i32 {
-        let file_handle = FileDescriptor(Rc::new(RefCell::new(Box::new(fd))));
-        self.insert_fd_with_min_fd(file_handle, 0)
+    /// Insert a new file description to the FdTable.
+    pub fn insert_new(&mut self, fd: impl FileDescription) -> i32 {
+        let file_handle = FileDescriptionRef::new(fd);
+        self.insert_ref_with_min_fd(file_handle, 0)
     }
 
-    /// Insert a new FD that is at least `min_fd`.
-    pub fn insert_fd_with_min_fd(&mut self, file_handle: FileDescriptor, min_fd: i32) -> i32 {
+    /// Insert a file description, giving it a file descriptor that is at least `min_fd`.
+    fn insert_ref_with_min_fd(&mut self, file_handle: FileDescriptionRef, min_fd: i32) -> i32 {
         // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
         // between used FDs, the find_map combinator will return it. If the first such unused FD
         // is after all other used FDs, the find_map combinator will return None, and we will use
@@ -282,12 +301,12 @@ impl FdTable {
         Some(fd.borrow_mut())
     }
 
-    pub fn dup(&self, fd: i32) -> Option<FileDescriptor> {
+    pub fn get_ref(&self, fd: i32) -> Option<FileDescriptionRef> {
         let fd = self.fds.get(&fd)?;
         Some(fd.clone())
     }
 
-    pub fn remove(&mut self, fd: i32) -> Option<FileDescriptor> {
+    pub fn remove(&mut self, fd: i32) -> Option<FileDescriptionRef> {
         self.fds.remove(&fd)
     }
 
@@ -298,33 +317,67 @@ impl FdTable {
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, i32> {
+    fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
-            return this.fd_not_found();
+        let Some(dup_fd) = this.machine.fds.get_ref(old_fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
-        Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0))
+        Ok(Scalar::from_i32(this.machine.fds.insert_ref_with_min_fd(dup_fd, 0)))
     }
 
-    fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> {
+    fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
-            return this.fd_not_found();
+        let Some(dup_fd) = this.machine.fds.get_ref(old_fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
         if new_fd != old_fd {
             // Close new_fd if it is previously opened.
             // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
-            if let Some(file_descriptor) = this.machine.fds.fds.insert(new_fd, dup_fd) {
+            if let Some(file_description) = this.machine.fds.fds.insert(new_fd, dup_fd) {
                 // Ignore close error (not interpreter's) according to dup2() doc.
-                file_descriptor.close(this.machine.communicate())?.ok();
+                file_description.close(this.machine.communicate())?.ok();
             }
         }
-        Ok(new_fd)
+        Ok(Scalar::from_i32(new_fd))
+    }
+
+    fn flock(&mut self, fd: i32, op: i32) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        let Some(file_descriptor) = this.machine.fds.get(fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
+        };
+
+        // We need to check that there aren't unsupported options in `op`.
+        let lock_sh = this.eval_libc_i32("LOCK_SH");
+        let lock_ex = this.eval_libc_i32("LOCK_EX");
+        let lock_nb = this.eval_libc_i32("LOCK_NB");
+        let lock_un = this.eval_libc_i32("LOCK_UN");
+
+        use FlockOp::*;
+        let parsed_op = if op == lock_sh {
+            SharedLock { nonblocking: false }
+        } else if op == lock_sh | lock_nb {
+            SharedLock { nonblocking: true }
+        } else if op == lock_ex {
+            ExclusiveLock { nonblocking: false }
+        } else if op == lock_ex | lock_nb {
+            ExclusiveLock { nonblocking: true }
+        } else if op == lock_un {
+            Unlock
+        } else {
+            throw_unsup_format!("unsupported flags {:#x}", op);
+        };
+
+        let result = file_descriptor.flock(this.machine.communicate(), parsed_op)?;
+        drop(file_descriptor);
+        // return `0` if flock is successful
+        let result = result.map(|()| 0i32);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
+    fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         if args.len() < 2 {
@@ -342,11 +395,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
             // always sets this flag when opening a file. However we still need to check that the
             // file itself is open.
-            if this.machine.fds.is_fd(fd) {
-                Ok(this.eval_libc_i32("FD_CLOEXEC"))
+            Ok(Scalar::from_i32(if this.machine.fds.is_fd(fd) {
+                this.eval_libc_i32("FD_CLOEXEC")
             } else {
-                this.fd_not_found()
-            }
+                this.fd_not_found()?
+            }))
         } else if cmd == this.eval_libc_i32("F_DUPFD")
             || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")
         {
@@ -362,16 +415,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             let start = this.read_scalar(&args[2])?.to_i32()?;
 
-            match this.machine.fds.dup(fd) {
-                Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)),
-                None => this.fd_not_found(),
+            match this.machine.fds.get_ref(fd) {
+                Some(dup_fd) =>
+                    Ok(Scalar::from_i32(this.machine.fds.insert_ref_with_min_fd(dup_fd, start))),
+                None => Ok(Scalar::from_i32(this.fd_not_found()?)),
             }
         } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
             // Reject if isolation is enabled.
             if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
                 this.reject_in_isolation("`fcntl`", reject_with)?;
                 this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-                return Ok(-1);
+                return Ok(Scalar::from_i32(-1));
             }
 
             this.ffullsync_fd(fd)
@@ -385,10 +439,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let fd = this.read_scalar(fd_op)?.to_i32()?;
 
-        let Some(file_descriptor) = this.machine.fds.remove(fd) else {
+        let Some(file_description) = this.machine.fds.remove(fd) else {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
-        let result = file_descriptor.close(this.machine.communicate())?;
+        let result = file_description.close(this.machine.communicate())?;
         // return `0` if close is successful
         let result = result.map(|()| 0i32);
         Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
@@ -416,7 +470,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         buf: Pointer,
         count: u64,
         offset: Option<i128>,
-    ) -> InterpResult<'tcx, i64> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         // Isolation check is done via `FileDescriptor` trait.
@@ -434,9 +488,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let communicate = this.machine.communicate();
 
         // We temporarily dup the FD to be able to retain mutable access to `this`.
-        let Some(fd) = this.machine.fds.dup(fd) else {
+        let Some(fd) = this.machine.fds.get_ref(fd) else {
             trace!("read: FD not found");
-            return this.fd_not_found();
+            return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
         };
 
         trace!("read: FD mapped to {fd:?}");
@@ -450,7 +504,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let Ok(offset) = u64::try_from(offset) else {
                     let einval = this.eval_libc("EINVAL");
                     this.set_last_error(einval)?;
-                    return Ok(-1);
+                    return Ok(Scalar::from_target_isize(-1, this));
                 };
                 fd.borrow_mut().pread(communicate, &mut bytes, offset, this)
             }
@@ -467,11 +521,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     buf,
                     bytes[..usize::try_from(read_bytes).unwrap()].iter().copied(),
                 )?;
-                Ok(read_bytes)
+                Ok(Scalar::from_target_isize(read_bytes, this))
             }
             Err(e) => {
                 this.set_last_error_from_io_error(e)?;
-                Ok(-1)
+                Ok(Scalar::from_target_isize(-1, this))
             }
         }
     }
@@ -482,7 +536,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         buf: Pointer,
         count: u64,
         offset: Option<i128>,
-    ) -> InterpResult<'tcx, i64> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         // Isolation check is done via `FileDescriptor` trait.
@@ -499,8 +553,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned();
         // We temporarily dup the FD to be able to retain mutable access to `this`.
-        let Some(fd) = this.machine.fds.dup(fd) else {
-            return this.fd_not_found();
+        let Some(fd) = this.machine.fds.get_ref(fd) else {
+            return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
         };
 
         let result = match offset {
@@ -509,7 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let Ok(offset) = u64::try_from(offset) else {
                     let einval = this.eval_libc("EINVAL");
                     this.set_last_error(einval)?;
-                    return Ok(-1);
+                    return Ok(Scalar::from_target_isize(-1, this));
                 };
                 fd.borrow_mut().pwrite(communicate, &bytes, offset, this)
             }
@@ -517,6 +571,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         drop(fd);
 
         let result = result?.map(|c| i64::try_from(c).unwrap());
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_target_isize(this.try_unwrap_io_result(result)?, this))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 966e590fcc4..57930f9807d 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -62,13 +62,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "unsetenv" => {
                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.unsetenv(name)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "setenv" => {
                 let [name, value, overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.read_scalar(overwrite)?.to_i32()?;
                 let result = this.setenv(name, value)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "getcwd" => {
                 let [buf, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -78,12 +78,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "chdir" => {
                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.chdir(path)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "getpid" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?;
                 let result = this.getpid()?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
 
             // File descriptors
@@ -93,7 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
                 let result = this.read(fd, buf, count, None)?;
-                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "write" => {
                 let [fd, buf, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -103,7 +103,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
                 let result = this.write(fd, buf, count, None)?;
                 // Now, `result` is the value we return back to the program.
-                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pread" => {
                 let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -112,7 +112,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let count = this.read_target_usize(count)?;
                 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let result = this.read(fd, buf, count, Some(offset))?;
-                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pwrite" => {
                 let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -123,7 +123,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
                 let result = this.write(fd, buf, count, Some(offset))?;
                 // Now, `result` is the value we return back to the program.
-                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pread64" => {
                 let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -132,7 +132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let count = this.read_target_usize(count)?;
                 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
                 let result = this.read(fd, buf, count, Some(offset))?;
-                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pwrite64" => {
                 let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -143,7 +143,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
                 let result = this.write(fd, buf, count, Some(offset))?;
                 // Now, `result` is the value we return back to the program.
-                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "close" => {
                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -155,20 +155,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // in `this.fcntl()`, so we do not use `check_shim` here.
                 this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
                 let result = this.fcntl(args)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "dup" => {
                 let [old_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
                 let new_fd = this.dup(old_fd)?;
-                this.write_scalar(Scalar::from_i32(new_fd), dest)?;
+                this.write_scalar(new_fd, dest)?;
             }
             "dup2" => {
                 let [old_fd, new_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
                 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
                 let result = this.dup2(old_fd, new_fd)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
+            }
+            "flock" => {
+                let [fd, op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let fd = this.read_scalar(fd)?.to_i32()?;
+                let op = this.read_scalar(op)?.to_i32()?;
+                let result = this.flock(fd, op)?;
+                this.write_scalar(result, dest)?;
             }
 
             // File and file system access
@@ -176,32 +183,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
                 this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
                 let result = this.open(args)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "unlink" => {
                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.unlink(path)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "symlink" => {
                 let [target, linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.symlink(target, linkpath)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "rename" => {
                 let [oldpath, newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.rename(oldpath, newpath)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "mkdir" => {
                 let [path, mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.mkdir(path, mode)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "rmdir" => {
                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.rmdir(path)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "opendir" => {
                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -211,7 +218,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "closedir" => {
                 let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.closedir(dirp)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "lseek64" => {
                 let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -248,12 +255,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "fsync" => {
                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.fsync(fd)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "fdatasync" => {
                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.fdatasync(fd)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "readlink" => {
                 let [pathname, buf, bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -278,7 +285,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "mkstemp" => {
                 let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.mkstemp(template)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
 
             // Sockets
@@ -294,7 +301,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "gettimeofday" => {
                 let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.gettimeofday(tv, tz)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "localtime_r" => {
                 let [timep, result_op] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
@@ -466,23 +473,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Synchronization primitives
             "pthread_mutexattr_init" => {
                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_mutexattr_init(attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_mutexattr_init(attr)?;
+                this.write_null(dest)?;
             }
             "pthread_mutexattr_settype" => {
                 let [attr, kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_mutexattr_settype(attr, kind)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_mutexattr_destroy" => {
                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_mutexattr_destroy(attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_mutexattr_destroy(attr)?;
+                this.write_null(dest)?;
             }
             "pthread_mutex_init" => {
                 let [mutex, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_mutex_init(mutex, attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_mutex_init(mutex, attr)?;
+                this.write_null(dest)?;
             }
             "pthread_mutex_lock" => {
                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -491,17 +498,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "pthread_mutex_trylock" => {
                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_mutex_trylock(mutex)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_mutex_unlock" => {
                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_mutex_unlock(mutex)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_mutex_destroy" => {
                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_mutex_destroy(mutex)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_mutex_destroy(mutex)?;
+                this.write_int(0, dest)?;
             }
             "pthread_rwlock_rdlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -510,7 +517,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "pthread_rwlock_tryrdlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_wrlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -519,22 +526,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "pthread_rwlock_trywrlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_rwlock_trywrlock(rwlock)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_unlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_rwlock_unlock(rwlock)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_rwlock_unlock(rwlock)?;
+                this.write_null(dest)?;
             }
             "pthread_rwlock_destroy" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_rwlock_destroy(rwlock)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_rwlock_destroy(rwlock)?;
+                this.write_null(dest)?;
             }
             "pthread_condattr_init" => {
                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_condattr_init(attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_condattr_init(attr)?;
+                this.write_null(dest)?;
             }
             "pthread_condattr_setclock" => {
                 let [attr, clock_id] =
@@ -545,28 +552,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "pthread_condattr_getclock" => {
                 let [attr, clock_id] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_condattr_getclock(attr, clock_id)?;
-                this.write_scalar(result, dest)?;
+                this.pthread_condattr_getclock(attr, clock_id)?;
+                this.write_null(dest)?;
             }
             "pthread_condattr_destroy" => {
                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_condattr_destroy(attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_condattr_destroy(attr)?;
+                this.write_null(dest)?;
             }
             "pthread_cond_init" => {
                 let [cond, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_cond_init(cond, attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_cond_init(cond, attr)?;
+                this.write_null(dest)?;
             }
             "pthread_cond_signal" => {
                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_cond_signal(cond)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_cond_signal(cond)?;
+                this.write_null(dest)?;
             }
             "pthread_cond_broadcast" => {
                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_cond_broadcast(cond)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_cond_broadcast(cond)?;
+                this.write_null(dest)?;
             }
             "pthread_cond_wait" => {
                 let [cond, mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -578,25 +585,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "pthread_cond_destroy" => {
                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_cond_destroy(cond)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_cond_destroy(cond)?;
+                this.write_null(dest)?;
             }
 
             // Threading
             "pthread_create" => {
                 let [thread, attr, start, arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_create(thread, attr, start, arg)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_create(thread, attr, start, arg)?;
+                this.write_null(dest)?;
             }
             "pthread_join" => {
                 let [thread, retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_join(thread, retval)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_join(thread, retval)?;
+                this.write_null(dest)?;
             }
             "pthread_detach" => {
                 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_detach(thread)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_detach(thread)?;
+                this.write_null(dest)?;
             }
             "pthread_self" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -605,13 +612,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "sched_yield" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.sched_yield()?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.sched_yield()?;
+                this.write_null(dest)?;
             }
             "nanosleep" => {
                 let [req, rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.nanosleep(req, rem)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "sched_getaffinity" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
@@ -640,23 +647,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if this.ptr_is_null(mask)? {
                     let einval = this.eval_libc("EFAULT");
                     this.set_last_error(einval)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
                     // we only copy whole chunks of size_of::<c_ulong>()
                     let einval = this.eval_libc("EINVAL");
                     this.set_last_error(einval)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
                     let cpuset = cpuset.clone();
                     // we only copy whole chunks of size_of::<c_ulong>()
                     let byte_count = Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
                     this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
-                    this.write_scalar(Scalar::from_i32(0), dest)?;
+                    this.write_null(dest)?;
                 } else {
                     // The thread whose ID is pid could not be found
                     let einval = this.eval_libc("ESRCH");
                     this.set_last_error(einval)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 }
             }
             "sched_setaffinity" => {
@@ -683,7 +690,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if this.ptr_is_null(mask)? {
                     let einval = this.eval_libc("EFAULT");
                     this.set_last_error(einval)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 } else {
                     // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
                     // Any unspecified bytes are treated as zero here (none of the CPUs are configured).
@@ -695,13 +702,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
                         Some(cpuset) => {
                             this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
-                            this.write_scalar(Scalar::from_i32(0), dest)?;
+                            this.write_null(dest)?;
                         }
                         None => {
                             // The intersection between the mask and the available CPUs was empty.
                             let einval = this.eval_libc("EINVAL");
                             this.set_last_error(einval)?;
-                            this.write_scalar(Scalar::from_i32(-1), dest)?;
+                            this.write_int(-1, dest)?;
                         }
                     }
                 }
@@ -759,10 +766,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if bufsize > 256 {
                     let err = this.eval_libc("EIO");
                     this.set_last_error(err)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 } else {
                     this.gen_random(buf, bufsize)?;
-                    this.write_scalar(Scalar::from_i32(0), dest)?;
+                    this.write_null(dest)?;
                 }
             }
             "getrandom" => {
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index f5695713dd3..d93374db818 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -16,6 +16,8 @@ use crate::shims::unix::*;
 use crate::*;
 use shims::time::system_time_to_duration;
 
+use self::fd::FlockOp;
+
 #[derive(Debug)]
 struct FileHandle {
     file: File,
@@ -127,6 +129,97 @@ impl FileDescription for FileHandle {
         }
     }
 
+    fn flock<'tcx>(
+        &self,
+        communicate_allowed: bool,
+        op: FlockOp,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        assert!(communicate_allowed, "isolation should have prevented even opening a file");
+        #[cfg(target_family = "unix")]
+        {
+            use std::os::fd::AsRawFd;
+
+            use FlockOp::*;
+            // We always use non-blocking call to prevent interpreter from being blocked
+            let (host_op, lock_nb) = match op {
+                SharedLock { nonblocking } => (libc::LOCK_SH | libc::LOCK_NB, nonblocking),
+                ExclusiveLock { nonblocking } => (libc::LOCK_EX | libc::LOCK_NB, nonblocking),
+                Unlock => (libc::LOCK_UN, false),
+            };
+
+            let fd = self.file.as_raw_fd();
+            let ret = unsafe { libc::flock(fd, host_op) };
+            let res = match ret {
+                0 => Ok(()),
+                -1 => {
+                    let err = io::Error::last_os_error();
+                    if !lock_nb && err.kind() == io::ErrorKind::WouldBlock {
+                        throw_unsup_format!("blocking `flock` is not currently supported");
+                    }
+                    Err(err)
+                }
+                ret => panic!("Unexpected return value from flock: {ret}"),
+            };
+            Ok(res)
+        }
+
+        #[cfg(target_family = "windows")]
+        {
+            use std::os::windows::io::AsRawHandle;
+            use windows_sys::Win32::{
+                Foundation::{ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, HANDLE, TRUE},
+                Storage::FileSystem::{
+                    LockFileEx, UnlockFile, LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY,
+                },
+            };
+            let fh = self.file.as_raw_handle() as HANDLE;
+
+            use FlockOp::*;
+            let (ret, lock_nb) = match op {
+                SharedLock { nonblocking } | ExclusiveLock { nonblocking } => {
+                    // We always use non-blocking call to prevent interpreter from being blocked
+                    let mut flags = LOCKFILE_FAIL_IMMEDIATELY;
+                    if matches!(op, ExclusiveLock { .. }) {
+                        flags |= LOCKFILE_EXCLUSIVE_LOCK;
+                    }
+                    let ret = unsafe { LockFileEx(fh, flags, 0, !0, !0, &mut std::mem::zeroed()) };
+                    (ret, nonblocking)
+                }
+                Unlock => {
+                    let ret = unsafe { UnlockFile(fh, 0, 0, !0, !0) };
+                    (ret, false)
+                }
+            };
+
+            let res = match ret {
+                TRUE => Ok(()),
+                FALSE => {
+                    let mut err = io::Error::last_os_error();
+                    let code: u32 = err.raw_os_error().unwrap().try_into().unwrap();
+                    if matches!(code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION) {
+                        if lock_nb {
+                            // The io error mapping does not know about these error codes,
+                            // so we translate it to `WouldBlock` manually.
+                            let desc = format!("LockFileEx wouldblock error: {err}");
+                            err = io::Error::new(io::ErrorKind::WouldBlock, desc);
+                        } else {
+                            throw_unsup_format!("blocking `flock` is not currently supported");
+                        }
+                    }
+                    Err(err)
+                }
+                _ => panic!("Unexpected return value: {ret}"),
+            };
+            Ok(res)
+        }
+
+        #[cfg(not(any(target_family = "unix", target_family = "windows")))]
+        {
+            let _ = op;
+            compile_error!("flock is supported only on UNIX and Windows hosts");
+        }
+    }
+
     fn is_tty(&self, communicate_allowed: bool) -> bool {
         communicate_allowed && self.file.is_terminal()
     }
@@ -302,7 +395,7 @@ fn maybe_sync_file(
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
+    fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
         if args.len() < 2 {
             throw_ub_format!(
                 "incorrect number of arguments for `open`: got {}, expected at least 2",
@@ -410,7 +503,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // if the flag contains `O_TMPFILE` then we return a graceful error
                 let eopnotsupp = this.eval_libc("EOPNOTSUPP");
                 this.set_last_error(eopnotsupp)?;
-                return Ok(-1);
+                return Ok(Scalar::from_i32(-1));
             }
         }
 
@@ -431,7 +524,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if path.is_symlink() {
                     let eloop = this.eval_libc("ELOOP");
                     this.set_last_error(eloop)?;
-                    return Ok(-1);
+                    return Ok(Scalar::from_i32(-1));
                 }
             }
             mirror |= o_nofollow;
@@ -447,14 +540,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`open`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let fd = options
             .open(path)
-            .map(|file| this.machine.fds.insert_fd(FileHandle { file, writable }));
+            .map(|file| this.machine.fds.insert_new(FileHandle { file, writable }));
 
-        this.try_unwrap_io_result(fd)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?))
     }
 
     fn lseek64(&mut self, fd: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> {
@@ -483,19 +576,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let communicate = this.machine.communicate();
 
-        let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
+        let Some(mut file_description) = this.machine.fds.get_mut(fd) else {
             return Ok(Scalar::from_i64(this.fd_not_found()?));
         };
-        let result = file_descriptor
+        let result = file_description
             .seek(communicate, seek_from)?
             .map(|offset| i64::try_from(offset).unwrap());
-        drop(file_descriptor);
+        drop(file_description);
 
         let result = this.try_unwrap_io_result(result)?;
         Ok(Scalar::from_i64(result))
     }
 
-    fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
@@ -504,18 +597,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`unlink`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let result = remove_file(path).map(|_| 0);
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn symlink(
         &mut self,
         target_op: &OpTy<'tcx>,
         linkpath_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         #[cfg(unix)]
         fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> {
             std::os::unix::fs::symlink(src, dst)
@@ -535,11 +628,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`symlink`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let result = create_link(&target, &linkpath).map(|_| 0);
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn macos_fbsd_stat(
@@ -638,7 +731,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         flags_op: &OpTy<'tcx>,    // Should be an `int`
         mask_op: &OpTy<'tcx>,     // Should be an `unsigned int`
         statxbuf_op: &OpTy<'tcx>, // Should be a `struct statx *`
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         this.assert_target_os("linux", "statx");
@@ -653,7 +746,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? {
             let efault = this.eval_libc("EFAULT");
             this.set_last_error(efault)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
@@ -695,7 +788,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.eval_libc("EBADF")
             };
             this.set_last_error(ecode)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         // the `_mask_op` parameter specifies the file information that the caller requested.
@@ -717,7 +810,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         let metadata = match metadata {
             Some(metadata) => metadata,
-            None => return Ok(-1),
+            None => return Ok(Scalar::from_i32(-1)),
         };
 
         // The `mode` field specifies the type of the file and the permissions over the file for
@@ -810,14 +903,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.project_field_named(&statxbuf, "stx_mtime")?,
         )?;
 
-        Ok(0)
+        Ok(Scalar::from_i32(0))
     }
 
     fn rename(
         &mut self,
         oldpath_op: &OpTy<'tcx>,
         newpath_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let oldpath_ptr = this.read_pointer(oldpath_op)?;
@@ -826,7 +919,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? {
             let efault = this.eval_libc("EFAULT");
             this.set_last_error(efault)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let oldpath = this.read_path_from_c_str(oldpath_ptr)?;
@@ -836,15 +929,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rename`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let result = rename(oldpath, newpath).map(|_| 0);
 
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         #[cfg_attr(not(unix), allow(unused_variables))]
@@ -860,7 +953,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`mkdir`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         #[cfg_attr(not(unix), allow(unused_mut))]
@@ -876,10 +969,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let result = builder.create(path).map(|_| 0i32);
 
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
@@ -888,12 +981,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rmdir`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let result = remove_dir(path).map(|_| 0i32);
 
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn opendir(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -1143,27 +1236,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }))
     }
 
-    fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let dirp = this.read_target_usize(dirp_op)?;
 
         // Reject if isolation is enabled.
-        if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
+        Ok(Scalar::from_i32(if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`closedir`", reject_with)?;
-            // Set error code as "EBADF" (bad fd)
-            return this.fd_not_found();
-        }
-
-        if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
+            this.fd_not_found()?
+        } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
             if let Some(entry) = open_dir.entry {
                 this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
             }
             drop(open_dir);
-            Ok(0)
+            0
         } else {
-            this.fd_not_found()
-        }
+            this.fd_not_found()?
+        }))
     }
 
     fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> {
@@ -1176,30 +1266,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
-        let Some(file_descriptor) = this.machine.fds.get(fd) else {
+        let Some(file_description) = this.machine.fds.get(fd) else {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
 
         // FIXME: Support ftruncate64 for all FDs
         let FileHandle { file, writable } =
-            file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
+            file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
                 err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors")
             })?;
 
         if *writable {
             if let Ok(length) = length.try_into() {
                 let result = file.set_len(length);
-                drop(file_descriptor);
+                drop(file_description);
                 let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
                 Ok(Scalar::from_i32(result))
             } else {
-                drop(file_descriptor);
+                drop(file_description);
                 let einval = this.eval_libc("EINVAL");
                 this.set_last_error(einval)?;
                 Ok(Scalar::from_i32(-1))
             }
         } else {
-            drop(file_descriptor);
+            drop(file_description);
             // The file is not writable
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
@@ -1207,7 +1297,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
     }
 
-    fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the
         // underlying disk to finish writing. In the interest of host compatibility,
         // we conservatively implement this with `sync_all`, which
@@ -1221,28 +1311,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fsync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return this.fd_not_found();
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
-        return self.ffullsync_fd(fd);
+        self.ffullsync_fd(fd)
     }
 
-    fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, i32> {
+    fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
-        let Some(file_descriptor) = this.machine.fds.get(fd) else {
-            return Ok(this.fd_not_found()?);
+        let Some(file_description) = this.machine.fds.get(fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } =
-            file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
+            file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
                 err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
             })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_all);
-        drop(file_descriptor);
-        this.try_unwrap_io_result(io_result)
+        drop(file_description);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
-    fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let fd = this.read_scalar(fd_op)?.to_i32()?;
@@ -1251,20 +1341,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fdatasync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return this.fd_not_found();
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
-        let Some(file_descriptor) = this.machine.fds.get(fd) else {
-            return Ok(this.fd_not_found()?);
+        let Some(file_description) = this.machine.fds.get(fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } =
-            file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
+            file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
                 err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors")
             })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_data);
-        drop(file_descriptor);
-        this.try_unwrap_io_result(io_result)
+        drop(file_description);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
     fn sync_file_range(
@@ -1302,18 +1392,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
-        let Some(file_descriptor) = this.machine.fds.get(fd) else {
+        let Some(file_description) = this.machine.fds.get(fd) else {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } =
-            file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
+            file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
                 err_unsup_format!(
                     "`sync_data_range` is only supported on file-backed file descriptors"
                 )
             })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_data);
-        drop(file_descriptor);
+        drop(file_description);
         Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
@@ -1441,7 +1531,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
     }
-    fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         use rand::seq::SliceRandom;
 
         // POSIX defines the template string.
@@ -1472,7 +1562,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`mkstemp`", reject_with)?;
             let eacc = this.eval_libc("EACCES");
             this.set_last_error(eacc)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         // Get the bytes of the suffix we expect in _target_ encoding.
@@ -1490,7 +1580,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if last_six_char_bytes != suffix_bytes {
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         // At this point we know we have 6 ASCII 'X' characters as a suffix.
@@ -1544,8 +1634,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             match file {
                 Ok(f) => {
-                    let fd = this.machine.fds.insert_fd(FileHandle { file: f, writable: true });
-                    return Ok(fd);
+                    let fd = this.machine.fds.insert_new(FileHandle { file: f, writable: true });
+                    return Ok(Scalar::from_i32(fd));
                 }
                 Err(e) =>
                     match e.kind() {
@@ -1556,7 +1646,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             // "On error, -1 is returned, and errno is set to
                             // indicate the error"
                             this.set_last_error_from_io_error(e)?;
-                            return Ok(-1);
+                            return Ok(Scalar::from_i32(-1));
                         }
                     },
             }
@@ -1565,7 +1655,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // We ran out of attempts to create the file, return an error.
         let eexist = this.eval_libc("EEXIST");
         this.set_last_error(eexist)?;
-        Ok(-1)
+        Ok(Scalar::from_i32(-1))
     }
 }
 
@@ -1609,11 +1699,11 @@ impl FileMetadata {
         ecx: &mut MiriInterpCx<'tcx>,
         fd: i32,
     ) -> InterpResult<'tcx, Option<FileMetadata>> {
-        let Some(file_descriptor) = ecx.machine.fds.get(fd) else {
+        let Some(file_description) = ecx.machine.fds.get(fd) else {
             return ecx.fd_not_found().map(|_: i32| None);
         };
 
-        let file = &file_descriptor
+        let file = &file_description
             .downcast_ref::<FileHandle>()
             .ok_or_else(|| {
                 err_unsup_format!(
@@ -1623,7 +1713,7 @@ impl FileMetadata {
             .file;
 
         let metadata = file.metadata();
-        drop(file_descriptor);
+        drop(file_description);
         FileMetadata::from_meta(ecx, metadata)
     }
 
diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs
index ad35d67876c..9127db3d004 100644
--- a/src/tools/miri/src/shims/unix/linux/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux/epoll.rs
@@ -64,7 +64,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             );
         }
 
-        let fd = this.machine.fds.insert_fd(Epoll::default());
+        let fd = this.machine.fds.insert_new(Epoll::default());
         Ok(Scalar::from_i32(fd))
     }
 
diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs
index 0fc28c72bb6..4ab8760d930 100644
--- a/src/tools/miri/src/shims/unix/linux/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs
@@ -178,7 +178,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             throw_unsup_format!("eventfd: encountered unknown unsupported flags {:#x}", flags);
         }
 
-        let fd = this.machine.fds.insert_fd(Event {
+        let fd = this.machine.fds.insert_new(Event {
             counter: val.into(),
             is_nonblock,
             clock: VClock::default(),
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index 20c6a234794..581f0db42e1 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -44,7 +44,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [dirfd, pathname, flags, mask, statxbuf] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
 
             // epoll, eventfd
@@ -97,7 +97,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "gettid" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.linux_gettid()?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
 
             // Dynamically invoked syscalls
@@ -176,12 +176,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "__libc_current_sigrtmin" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
-                this.write_scalar(Scalar::from_i32(SIGRTMIN), dest)?;
+                this.write_int(SIGRTMIN, dest)?;
             }
             "__libc_current_sigrtmax" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
-                this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?;
+                this.write_int(SIGRTMAX, dest)?;
             }
 
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs
index cc0f932e038..455820a9e6e 100644
--- a/src/tools/miri/src/shims/unix/socket.rs
+++ b/src/tools/miri/src/shims/unix/socket.rs
@@ -219,8 +219,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         let fds = &mut this.machine.fds;
-        let sv0 = fds.insert_fd(socketpair_0);
-        let sv1 = fds.insert_fd(socketpair_1);
+        let sv0 = fds.insert_new(socketpair_0);
+        let sv1 = fds.insert_new(socketpair_1);
         let sv0 = Scalar::from_int(sv0, sv.layout.size);
         let sv1 = Scalar::from_int(sv1, sv.layout.size);
 
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index e8653117ae9..0b889b11822 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -363,20 +363,20 @@ fn cond_set_clock_id<'tcx>(
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT");
         mutexattr_set_kind(this, attr_op, default_kind)?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_mutexattr_settype(
         &mut self,
         attr_op: &OpTy<'tcx>,
         kind_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let kind = this.read_scalar(kind_op)?.to_i32()?;
@@ -407,13 +407,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             mutexattr_set_kind(this, attr_op, kind)?;
         } else {
             let einval = this.eval_libc_i32("EINVAL");
-            return Ok(einval);
+            return Ok(Scalar::from_i32(einval));
         }
 
-        Ok(0)
+        Ok(Scalar::from_i32(0))
     }
 
-    fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit.
@@ -435,14 +435,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
         )?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_mutex_init(
         &mut self,
         mutex_op: &OpTy<'tcx>,
         attr_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let attr = this.read_pointer(attr_op)?;
@@ -457,7 +457,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         mutex_set_kind(this, mutex_op, kind)?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_mutex_lock(
@@ -501,25 +501,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let kind = mutex_get_kind(this, mutex_op)?;
         let id = mutex_get_id(this, mutex_op)?;
 
-        if this.mutex_is_locked(id) {
+        Ok(Scalar::from_i32(if this.mutex_is_locked(id) {
             let owner_thread = this.mutex_get_owner(id);
             if owner_thread != this.active_thread() {
-                Ok(this.eval_libc_i32("EBUSY"))
+                this.eval_libc_i32("EBUSY")
             } else {
                 if is_mutex_kind_default(this, kind)?
                     || is_mutex_kind_normal(this, kind)?
                     || kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
                 {
-                    Ok(this.eval_libc_i32("EBUSY"))
+                    this.eval_libc_i32("EBUSY")
                 } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
                     this.mutex_lock(id);
-                    Ok(0)
+                    0
                 } else {
                     throw_unsup_format!(
                         "called pthread_mutex_trylock on an unsupported type of mutex"
@@ -529,11 +529,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else {
             // The mutex is unlocked. Let's lock it.
             this.mutex_lock(id);
-            Ok(0)
-        }
+            0
+        }))
     }
 
-    fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let kind = mutex_get_kind(this, mutex_op)?;
@@ -541,7 +541,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if let Some(_old_locked_count) = this.mutex_unlock(id)? {
             // The mutex was locked by the current thread.
-            Ok(0)
+            Ok(Scalar::from_i32(0))
         } else {
             // The mutex was locked by another thread or not locked at all. See
             // the “Unlock When Not Owner” column in
@@ -557,14 +557,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
                 || kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")
             {
-                Ok(this.eval_libc_i32("EPERM"))
+                Ok(Scalar::from_i32(this.eval_libc_i32("EPERM")))
             } else {
                 throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex");
             }
         }
     }
 
-    fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let id = mutex_get_id(this, mutex_op)?;
@@ -583,7 +583,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )?;
         // FIXME: delete interpreter state associated with this mutex.
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_rwlock_rdlock(
@@ -605,16 +605,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let id = rwlock_get_id(this, rwlock_op)?;
 
         if this.rwlock_is_write_locked(id) {
-            Ok(this.eval_libc_i32("EBUSY"))
+            Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
         } else {
             this.rwlock_reader_lock(id);
-            Ok(0)
+            Ok(Scalar::from_i32(0))
         }
     }
 
@@ -649,35 +649,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let id = rwlock_get_id(this, rwlock_op)?;
 
         if this.rwlock_is_locked(id) {
-            Ok(this.eval_libc_i32("EBUSY"))
+            Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
         } else {
             this.rwlock_writer_lock(id);
-            Ok(0)
+            Ok(Scalar::from_i32(0))
         }
     }
 
-    fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let id = rwlock_get_id(this, rwlock_op)?;
 
         #[allow(clippy::if_same_then_else)]
-        if this.rwlock_reader_unlock(id)? {
-            Ok(0)
-        } else if this.rwlock_writer_unlock(id)? {
-            Ok(0)
+        if this.rwlock_reader_unlock(id)? || this.rwlock_writer_unlock(id)? {
+            Ok(())
         } else {
             throw_ub_format!("unlocked an rwlock that was not locked by the active thread");
         }
     }
 
-    fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let id = rwlock_get_id(this, rwlock_op)?;
@@ -695,10 +693,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )?;
         // FIXME: delete interpreter state associated with this rwlock.
 
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         // no clock attribute on macOS
@@ -710,7 +708,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             condattr_set_clock_id(this, attr_op, default_clock_id)?;
         }
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_condattr_setclock(
@@ -737,16 +735,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         attr_op: &OpTy<'tcx>,
         clk_id_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, Scalar> {
+    ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let clock_id = condattr_get_clock_id(this, attr_op)?;
         this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?;
 
-        Ok(Scalar::from_i32(0))
+        Ok(())
     }
 
-    fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit.
@@ -761,14 +759,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
         )?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_cond_init(
         &mut self,
         cond_op: &OpTy<'tcx>,
         attr_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let attr = this.read_pointer(attr_op)?;
@@ -784,21 +782,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         cond_set_clock_id(this, cond_op, clock_id)?;
 
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
         let id = cond_get_id(this, cond_op)?;
         this.condvar_signal(id)?;
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
         let id = cond_get_id(this, cond_op)?;
         while this.condvar_signal(id)? {}
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_cond_wait(
@@ -869,7 +867,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let id = cond_get_id(this, cond_op)?;
@@ -885,6 +883,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
         // FIXME: delete interpreter state associated with this condvar.
 
-        Ok(0)
+        Ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 6fe331ba623..56e8270aa62 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -1,5 +1,4 @@
 use crate::*;
-use rustc_middle::ty::layout::LayoutOf;
 use rustc_target::spec::abi::Abi;
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -10,7 +9,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         _attr: &OpTy<'tcx>,
         start_routine: &OpTy<'tcx>,
         arg: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let thread_info_place = this.deref_pointer_as(thread, this.libc_ty_layout("pthread_t"))?;
@@ -24,17 +23,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             start_routine,
             Abi::C { unwind: false },
             func_arg,
-            this.layout_of(this.tcx.types.usize)?,
+            this.machine.layouts.mut_raw_ptr,
         )?;
 
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_join(
-        &mut self,
-        thread: &OpTy<'tcx>,
-        retval: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    fn pthread_join(&mut self, thread: &OpTy<'tcx>, retval: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         if !this.ptr_is_null(this.read_pointer(retval)?)? {
@@ -45,10 +40,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
         this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?;
 
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
@@ -57,7 +52,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             /*allow_terminated_joined*/ false,
         )?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> {
@@ -113,11 +108,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(if success { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") })
     }
 
-    fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
+    fn sched_yield(&mut self) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         this.yield_active_thread();
 
-        Ok(0)
+        Ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs
index 77ae06bd5c2..495df18a6ea 100644
--- a/src/tools/miri/src/shims/windows/env.rs
+++ b/src/tools/miri/src/shims/windows/env.rs
@@ -197,11 +197,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     #[allow(non_snake_case)]
-    fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> {
+    fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os("windows", "GetCurrentProcessId");
 
-        Ok(this.get_pid())
+        Ok(Scalar::from_u32(this.get_pid()))
     }
 
     #[allow(non_snake_case)]
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 71f6a2bc033..f840ba16165 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -141,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "GetCurrentProcessId" => {
                 let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 let result = this.GetCurrentProcessId()?;
-                this.write_int(result, dest)?;
+                this.write_scalar(result, dest)?;
             }
 
             // File related shims
@@ -372,7 +372,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
 
                 // Return success (`1`).
-                this.write_scalar(Scalar::from_i32(1), dest)?;
+                this.write_int(1, dest)?;
             }
 
             // Access to command-line arguments
@@ -563,7 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 this.gen_random(ptr, len)?;
-                this.write_scalar(Scalar::from_i32(1), dest)?;
+                this.write_int(1, dest)?;
             }
             "BCryptGenRandom" => {
                 // used by getrandom 0.2
@@ -627,7 +627,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 this.CloseHandle(handle)?;
 
-                this.write_scalar(Scalar::from_u32(1), dest)?;
+                this.write_int(1, dest)?;
             }
             "GetModuleFileNameW" => {
                 let [handle, filename, size] =
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index d534fdab291..e94bef52952 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.21.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
 dependencies = [
  "gimli",
 ]
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "backtrace"
-version = "0.3.71"
+version = "0.3.73"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
+checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
 dependencies = [
  "addr2line",
  "cc",
@@ -34,9 +34,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "bumpalo"
@@ -46,9 +46,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "cc"
-version = "1.0.96"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd"
+checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
 
 [[package]]
 name = "cfg-if"
@@ -58,12 +58,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "errno"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -85,9 +85,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -98,9 +98,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.28.1"
+version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
 
 [[package]]
 name = "hermit-abi"
@@ -119,46 +119,47 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.154"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "log"
-version = "0.4.21"
+version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
 [[package]]
 name = "memchr"
-version = "2.7.2"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.2"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
 dependencies = [
  "adler",
 ]
 
 [[package]]
 name = "mio"
-version = "0.8.11"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
 dependencies = [
+ "hermit-abi",
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -166,13 +167,13 @@ name = "miri-test-deps"
 version = "0.1.0"
 dependencies = [
  "getrandom 0.1.16",
- "getrandom 0.2.14",
+ "getrandom 0.2.15",
  "libc",
  "num_cpus",
  "page_size",
  "tempfile",
  "tokio",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -187,9 +188,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.32.2"
+version = "0.36.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
+checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
 dependencies = [
  "memchr",
 ]
@@ -218,9 +219,9 @@ checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.81"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 dependencies = [
  "unicode-ident",
 ]
@@ -236,9 +237,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustix"
@@ -250,7 +251,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -269,14 +270,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.60"
+version = "2.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -285,38 +286,38 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.10.1"
+version = "3.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "once_cell",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "tokio"
-version = "1.37.0"
+version = "1.39.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
+checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
 dependencies = [
  "backtrace",
  "libc",
  "mio",
- "num_cpus",
  "pin-project-lite",
  "signal-hook-registry",
  "socket2",
  "tokio-macros",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.2.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
+checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -419,139 +420,73 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.5",
+ "windows-targets",
 ]
 
 [[package]]
 name = "windows-targets"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
-dependencies = [
- "windows_aarch64_gnullvm 0.52.5",
- "windows_aarch64_msvc 0.52.5",
- "windows_i686_gnu 0.52.5",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.5",
- "windows_x86_64_gnu 0.52.5",
- "windows_x86_64_gnullvm 0.52.5",
- "windows_x86_64_msvc 0.52.5",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
 name = "windows_i686_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
index 96dd99e8844..39b1c3007cb 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
@@ -1,11 +1,12 @@
 //@ignore-target-windows: No pthreads on Windows
+//~^ERROR: calling a function with more arguments than it expected
 
 //! The thread function must have exactly one argument.
 
 use std::{mem, ptr};
 
 extern "C" fn thread_start() -> *mut libc::c_void {
-    panic!() //~ ERROR: callee has fewer arguments than expected
+    panic!()
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
index ca6a05ac7dd..aa67420c753 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
@@ -1,14 +1,10 @@
-error: Undefined Behavior: callee has fewer arguments than expected
-  --> $DIR/libc_pthread_create_too_few_args.rs:LL:CC
-   |
-LL |     panic!()
-   |     ^^^^^^^^ callee has fewer arguments than expected
+error: Undefined Behavior: calling a function with more arguments than it expected
    |
+   = note: calling a function with more arguments than it expected
+   = note: (no span available)
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE on thread `unnamed-ID`:
-   = note: inside `thread_start` at RUSTLIB/core/src/panic.rs:LL:CC
-   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
index d8fbc68d344..fc2ab71dff7 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
@@ -1,11 +1,12 @@
 //@ignore-target-windows: No pthreads on Windows
+//~^ERROR: calling a function with fewer arguments than it requires
 
 //! The thread function must have exactly one argument.
 
 use std::{mem, ptr};
 
 extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void {
-    panic!() //~ ERROR: callee has more arguments than expected
+    panic!()
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
index 6ab48a76666..4de947b1694 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
@@ -1,14 +1,10 @@
-error: Undefined Behavior: callee has more arguments than expected
-  --> $DIR/libc_pthread_create_too_many_args.rs:LL:CC
-   |
-LL |     panic!()
-   |     ^^^^^^^^ callee has more arguments than expected
+error: Undefined Behavior: calling a function with fewer arguments than it requires
    |
+   = note: calling a function with fewer arguments than it requires
+   = note: (no span available)
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE on thread `unnamed-ID`:
-   = note: inside `thread_start` at RUSTLIB/core/src/panic.rs:LL:CC
-   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail-dep/tokio/sleep.stderr b/src/tools/miri/tests/fail-dep/tokio/sleep.stderr
index 4b12729bbff..6d19faab905 100644
--- a/src/tools/miri/tests/fail-dep/tokio/sleep.stderr
+++ b/src/tools/miri/tests/fail-dep/tokio/sleep.stderr
@@ -2,7 +2,7 @@ error: unsupported operation: returning ready events from epoll_wait is not yet
   --> CARGO_REGISTRY/.../epoll.rs:LL:CC
    |
 LL | /         syscall!(epoll_wait(
-LL | |             self.ep,
+LL | |             self.ep.as_raw_fd(),
 LL | |             events.as_mut_ptr(),
 LL | |             events.capacity() as i32,
 LL | |             timeout,
diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
index fd667fbe454..6a7a26710d1 100644
--- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
+++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
@@ -9,7 +9,7 @@ fn main() {
         // Make sure we check the ABI when Miri itself invokes a function
         // as part of a shim implementation.
         std::intrinsics::catch_unwind(
-            //~^ ERROR: calling a function with ABI C using caller ABI Rust
+            //~^ ERROR: calling a function with calling convention C using calling convention Rust
             std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn),
             std::ptr::null_mut(),
             |_, _| unreachable!(),
diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
index 501f17c86d6..890fed09e48 100644
--- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
+++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with ABI C using caller ABI Rust
+error: Undefined Behavior: calling a function with calling convention C using calling convention Rust
   --> $DIR/check_callback_abi.rs:LL:CC
    |
 LL | /         std::intrinsics::catch_unwind(
@@ -7,7 +7,7 @@ LL | |             std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn),
 LL | |             std::ptr::null_mut(),
 LL | |             |_, _| unreachable!(),
 LL | |         );
-   | |_________^ calling a function with ABI C using caller ABI Rust
+   | |_________^ calling a function with calling convention C using calling convention Rust
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/miri_start_wrong_sig.rs b/src/tools/miri/tests/fail/miri_start_wrong_sig.rs
new file mode 100644
index 00000000000..dac83d817ba
--- /dev/null
+++ b/src/tools/miri/tests/fail/miri_start_wrong_sig.rs
@@ -0,0 +1,21 @@
+//@compile-flags: -Cpanic=abort
+//@error-in-other-file: `miri_start` must have the following signature:
+#![no_main]
+#![no_std]
+
+use core::fmt::Write;
+
+#[path = "../utils/mod.no_std.rs"]
+mod utils;
+
+#[no_mangle]
+fn miri_start() -> isize {
+    //~^ ERROR: mismatched types
+    writeln!(utils::MiriStdout, "Hello from miri_start!").unwrap();
+    0
+}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr b/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr
new file mode 100644
index 00000000000..62171917116
--- /dev/null
+++ b/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/miri_start_wrong_sig.rs:LL:CC
+   |
+LL | fn miri_start() -> isize {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn(isize, *const *const u8) -> _`
+              found signature `fn() -> _`
+
+error: `miri_start` must have the following signature:
+       fn miri_start(argc: isize, argv: *const *const u8) -> isize
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/tools/miri/tests/fail/no_main.rs b/src/tools/miri/tests/fail/no_main.rs
index 01b8c7bd66b..4bbd820a636 100644
--- a/src/tools/miri/tests/fail/no_main.rs
+++ b/src/tools/miri/tests/fail/no_main.rs
@@ -1,2 +1,2 @@
-//@error-in-other-file: miri can only run programs that have a main function
+//@error-in-other-file: Miri can only run programs that have a main function.
 #![no_main]
diff --git a/src/tools/miri/tests/fail/no_main.stderr b/src/tools/miri/tests/fail/no_main.stderr
index 1c4fc88989b..e9b9e5d65b1 100644
--- a/src/tools/miri/tests/fail/no_main.stderr
+++ b/src/tools/miri/tests/fail/no_main.stderr
@@ -1,4 +1,11 @@
-error: miri can only run programs that have a main function
+error: Miri can only run programs that have a main function.
+       Alternatively, you can export a `miri_start` function:
+       
+       #[cfg(miri)]
+       #[no_mangle]
+       fn miri_start(argc: isize, argv: *const *const u8) -> isize {
+           // Call the actual start function that your project implements, based on your target's conventions.
+       }
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs
new file mode 100644
index 00000000000..17b81f29cfe
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs
@@ -0,0 +1,8 @@
+//@compile-flags: -Zmiri-recursive-validation
+
+fn main() {
+    let x = 3u8;
+    let xref = &x;
+    let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; //~ERROR: encountered 0x03, but expected a boolean
+    let _val = *xref_wrong_type;
+}
diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr
new file mode 100644
index 00000000000..2b2fa9b8a20
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value at .<deref>: encountered 0x03, but expected a boolean
+  --> $DIR/recursive-validity-ref-bool.rs:LL:CC
+   |
+LL |     let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) };
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered 0x03, but expected a boolean
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/recursive-validity-ref-bool.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
new file mode 100644
index 00000000000..3f7f9b18be9
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
@@ -0,0 +1,70 @@
+//@ignore-target-windows: File handling is not implemented yet
+//@compile-flags: -Zmiri-disable-isolation
+
+use std::{fs::File, io::Error, os::fd::AsRawFd};
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+
+fn main() {
+    let bytes = b"Hello, World!\n";
+    let path = utils::prepare_with_content("miri_test_fs_shared_lock.txt", bytes);
+
+    let files: Vec<File> = (0..3).map(|_| File::open(&path).unwrap()).collect();
+
+    // Test that we can apply many shared locks
+    for file in files.iter() {
+        let fd = file.as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_SH) };
+        if ret != 0 {
+            panic!("flock error: {}", Error::last_os_error());
+        }
+    }
+
+    // Test that shared lock prevents exclusive lock
+    {
+        let fd = files[0].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB) };
+        assert_eq!(ret, -1);
+        let err = Error::last_os_error().raw_os_error().unwrap();
+        assert_eq!(err, libc::EWOULDBLOCK);
+    }
+
+    // Unlock shared lock
+    for file in files.iter() {
+        let fd = file.as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_UN) };
+        if ret != 0 {
+            panic!("flock error: {}", Error::last_os_error());
+        }
+    }
+
+    // Take exclusive lock
+    {
+        let fd = files[0].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_EX) };
+        assert_eq!(ret, 0);
+    }
+
+    // Test that shared lock prevents exclusive and shared locks
+    {
+        let fd = files[1].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB) };
+        assert_eq!(ret, -1);
+        let err = Error::last_os_error().raw_os_error().unwrap();
+        assert_eq!(err, libc::EWOULDBLOCK);
+
+        let fd = files[2].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB) };
+        assert_eq!(ret, -1);
+        let err = Error::last_os_error().raw_os_error().unwrap();
+        assert_eq!(err, libc::EWOULDBLOCK);
+    }
+
+    // Unlock exclusive lock
+    {
+        let fd = files[0].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_UN) };
+        assert_eq!(ret, 0);
+    }
+}
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs
index a226783155b..40b8e23a33c 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.rs
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs
@@ -1,7 +1,7 @@
 #![feature(start)]
 #![no_std]
-//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort
-//@normalize-stderr-test: "id 20" -> "id $$ALLOC"
+//@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort
+//@normalize-stderr-test: "id 21" -> "id $$ALLOC"
 //@only-target-linux: alloc IDs differ between OSes (due to extern static allocations)
 
 extern "Rust" {
diff --git a/src/tools/miri/tests/pass/async-fn.rs b/src/tools/miri/tests/pass/async-fn.rs
index 13400c88c71..67ec2e26b30 100644
--- a/src/tools/miri/tests/pass/async-fn.rs
+++ b/src/tools/miri/tests/pass/async-fn.rs
@@ -59,6 +59,7 @@ async fn hello_world() {
 }
 
 // This example comes from https://github.com/rust-lang/rust/issues/115145
+#[allow(unreachable_patterns)]
 async fn uninhabited_variant() {
     async fn unreachable(_: Never) {}
 
diff --git a/src/tools/miri/tests/pass/enums.rs b/src/tools/miri/tests/pass/enums.rs
index ac7aafc1bb2..1dafef025e9 100644
--- a/src/tools/miri/tests/pass/enums.rs
+++ b/src/tools/miri/tests/pass/enums.rs
@@ -43,6 +43,7 @@ fn discriminant_overflow() {
     }
 }
 
+#[allow(unreachable_patterns)]
 fn more_discriminant_overflow() {
     pub enum Infallible {}
 
diff --git a/src/tools/miri/tests/pass/miri_start.rs b/src/tools/miri/tests/pass/miri_start.rs
new file mode 100644
index 00000000000..756a1f60be1
--- /dev/null
+++ b/src/tools/miri/tests/pass/miri_start.rs
@@ -0,0 +1,19 @@
+//@compile-flags: -Cpanic=abort
+#![no_main]
+#![no_std]
+
+use core::fmt::Write;
+
+#[path = "../utils/mod.no_std.rs"]
+mod utils;
+
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
+    writeln!(utils::MiriStdout, "Hello from miri_start!").unwrap();
+    0
+}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/src/tools/miri/tests/pass/miri_start.stdout b/src/tools/miri/tests/pass/miri_start.stdout
new file mode 100644
index 00000000000..1c9e8489b57
--- /dev/null
+++ b/src/tools/miri/tests/pass/miri_start.stdout
@@ -0,0 +1 @@
+Hello from miri_start!
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index 3a8b098ccbe..95f8b054102 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -73,7 +73,7 @@ fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
         stdout_filters: stdout_filters().into(),
         mode,
         program,
-        out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("ui"),
+        out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri_ui"),
         edition: Some("2021".into()), // keep in sync with `./miri run`
         threads: std::env::var("MIRI_TEST_THREADS")
             .ok()
diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs
index bc6ec7566e5..0d7b5cb9838 100644
--- a/src/tools/run-make-support/src/artifact_names.rs
+++ b/src/tools/run-make-support/src/artifact_names.rs
@@ -38,6 +38,17 @@ pub fn dynamic_lib_name(name: &str) -> String {
     format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION)
 }
 
+/// Construct the name of the import library for the dynamic library, exclusive to MSVC and
+/// accepted by link.exe.
+#[track_caller]
+#[must_use]
+pub fn msvc_import_dynamic_lib_name(name: &str) -> String {
+    assert!(is_msvc(), "this function is exclusive to MSVC");
+    assert!(!name.contains(char::is_whitespace), "import library name cannot contain whitespace");
+
+    format!("{name}.dll.lib")
+}
+
 /// Construct the dynamic library extension based on the target.
 #[must_use]
 pub fn dynamic_lib_extension() -> &'static str {
diff --git a/src/tools/run-make-support/src/external_deps/c_build.rs b/src/tools/run-make-support/src/external_deps/c_build.rs
index 15e02d04393..f8d1666adda 100644
--- a/src/tools/run-make-support/src/external_deps/c_build.rs
+++ b/src/tools/run-make-support/src/external_deps/c_build.rs
@@ -1,6 +1,5 @@
 use std::path::PathBuf;
 
-use super::cygpath::get_windows_path;
 use crate::artifact_names::{dynamic_lib_name, static_lib_name};
 use crate::external_deps::cc::{cc, cxx};
 use crate::external_deps::llvm::llvm_ar;
@@ -13,14 +12,31 @@ use crate::targets::{is_darwin, is_msvc, is_windows};
 /// Built from a C file.
 #[track_caller]
 pub fn build_native_static_lib(lib_name: &str) -> PathBuf {
+    build_native_static_lib_internal(lib_name, false)
+}
+
+/// Builds an optimized static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
+/// Built from a C file.
+#[track_caller]
+pub fn build_native_static_lib_optimized(lib_name: &str) -> PathBuf {
+    build_native_static_lib_internal(lib_name, true)
+}
+
+#[track_caller]
+fn build_native_static_lib_internal(lib_name: &str, optimzed: bool) -> PathBuf {
     let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
     let src = format!("{lib_name}.c");
     let lib_path = static_lib_name(lib_name);
-    if is_msvc() {
-        cc().arg("-c").out_exe(&obj_file).input(src).run();
-    } else {
-        cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run();
-    };
+
+    let mut cc = cc();
+    if !is_msvc() {
+        cc.arg("-v");
+    }
+    if optimzed {
+        cc.optimize();
+    }
+    cc.arg("-c").out_exe(&obj_file).input(src).optimize().run();
+
     let obj_file = if is_msvc() {
         PathBuf::from(format!("{lib_name}.obj"))
     } else {
@@ -44,8 +60,7 @@ pub fn build_native_dynamic_lib(lib_name: &str) -> PathBuf {
     };
     let obj_file = if is_msvc() { format!("{lib_name}.obj") } else { format!("{lib_name}.o") };
     if is_msvc() {
-        let mut out_arg = "-out:".to_owned();
-        out_arg.push_str(&get_windows_path(&lib_path));
+        let out_arg = format!("-out:{lib_path}");
         cc().input(&obj_file).args(&["-link", "-dll", &out_arg]).run();
     } else if is_darwin() {
         cc().out_exe(&lib_path).input(&obj_file).args(&["-dynamiclib", "-Wl,-dylib"]).run();
diff --git a/src/tools/run-make-support/src/external_deps/cc.rs b/src/tools/run-make-support/src/external_deps/cc.rs
index 39ac3efef39..011ad89e170 100644
--- a/src/tools/run-make-support/src/external_deps/cc.rs
+++ b/src/tools/run-make-support/src/external_deps/cc.rs
@@ -1,7 +1,5 @@
 use std::path::Path;
 
-// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency?
-use super::cygpath::get_windows_path;
 use crate::command::Command;
 use crate::{env_var, is_msvc, is_windows, uname};
 
@@ -97,12 +95,12 @@ impl Cc {
 
         if is_msvc() {
             path.set_extension("exe");
-            let fe_path = get_windows_path(&path);
+            let fe_path = path.clone();
             path.set_extension("");
             path.set_extension("obj");
-            let fo_path = get_windows_path(path);
-            self.cmd.arg(format!("-Fe:{fe_path}"));
-            self.cmd.arg(format!("-Fo:{fo_path}"));
+            let fo_path = path;
+            self.cmd.arg(format!("-Fe:{}", fe_path.to_str().unwrap()));
+            self.cmd.arg(format!("-Fo:{}", fo_path.to_str().unwrap()));
         } else {
             self.cmd.arg("-o");
             self.cmd.arg(name);
@@ -117,6 +115,17 @@ impl Cc {
         self.cmd.arg(path.as_ref());
         self
     }
+
+    /// Optimize the output.
+    /// Equivalent to `-O3` for GNU-compatible linkers or `-O2` for MSVC linkers.
+    pub fn optimize(&mut self) -> &mut Self {
+        if is_msvc() {
+            self.cmd.arg("-O2");
+        } else {
+            self.cmd.arg("-O3");
+        }
+        self
+    }
 }
 
 /// `EXTRACFLAGS`
diff --git a/src/tools/run-make-support/src/external_deps/clang.rs b/src/tools/run-make-support/src/external_deps/clang.rs
index 2b0712541cd..2d110c6825e 100644
--- a/src/tools/run-make-support/src/external_deps/clang.rs
+++ b/src/tools/run-make-support/src/external_deps/clang.rs
@@ -1,7 +1,7 @@
 use std::path::Path;
 
 use crate::command::Command;
-use crate::{bin_name, env_var};
+use crate::{bin_name, cwd, env_var};
 
 /// Construct a new `clang` invocation. `clang` is not always available for all targets.
 #[track_caller]
@@ -23,7 +23,8 @@ impl Clang {
     #[track_caller]
     pub fn new() -> Self {
         let clang = env_var("CLANG");
-        let cmd = Command::new(clang);
+        let mut cmd = Command::new(clang);
+        cmd.arg("-L").arg(cwd());
         Self { cmd }
     }
 
diff --git a/src/tools/run-make-support/src/external_deps/cygpath.rs b/src/tools/run-make-support/src/external_deps/cygpath.rs
deleted file mode 100644
index 07d8e840a63..00000000000
--- a/src/tools/run-make-support/src/external_deps/cygpath.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use std::panic;
-use std::path::Path;
-
-use crate::command::Command;
-use crate::util::handle_failed_output;
-
-/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
-/// available on the platform!
-///
-/// # FIXME
-///
-/// FIXME(jieyouxu): we should consider not depending on `cygpath`.
-///
-/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style
-/// > pathnames and vice versa.
-/// >
-/// > [irrelevant entries omitted...]
-/// >
-/// > `-w, --windows         print Windows form of NAMEs (C:\WINNT)`
-/// >
-/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*.
-#[track_caller]
-#[must_use]
-pub fn get_windows_path<P: AsRef<Path>>(path: P) -> String {
-    let caller = panic::Location::caller();
-    let mut cygpath = Command::new("cygpath");
-    cygpath.arg("-w");
-    cygpath.arg(path.as_ref());
-    let output = cygpath.run();
-    if !output.status().success() {
-        handle_failed_output(&cygpath, output, caller.line());
-    }
-    // cygpath -w can attach a newline
-    output.stdout_utf8().trim().to_string()
-}
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index c06cefa91a9..dc651fdd820 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -151,7 +151,8 @@ impl LlvmReadobj {
         self
     }
 
-    /// Pass `--symbols` to display the symbol.
+    /// Pass `--symbols` to display the symbol table, including both local
+    /// and global symbols.
     pub fn symbols(&mut self) -> &mut Self {
         self.cmd.arg("--symbols");
         self
@@ -246,6 +247,12 @@ impl LlvmObjdump {
         self.cmd.arg(path.as_ref());
         self
     }
+
+    /// Disassemble all executable sections found in the input files.
+    pub fn disassemble(&mut self) -> &mut Self {
+        self.cmd.arg("-d");
+        self
+    }
 }
 
 impl LlvmAr {
diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs
index a2dc426f3f2..f7c84724d0e 100644
--- a/src/tools/run-make-support/src/external_deps/mod.rs
+++ b/src/tools/run-make-support/src/external_deps/mod.rs
@@ -9,6 +9,3 @@ pub mod llvm;
 pub mod python;
 pub mod rustc;
 pub mod rustdoc;
-
-// Library-internal external dependency.
-mod cygpath;
diff --git a/src/tools/run-make-support/src/fs.rs b/src/tools/run-make-support/src/fs.rs
index 0a796161633..2c35ba52a62 100644
--- a/src/tools/run-make-support/src/fs.rs
+++ b/src/tools/run-make-support/src/fs.rs
@@ -9,11 +9,19 @@ pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
     if link.as_ref().exists() {
         std::fs::remove_dir(link.as_ref()).unwrap();
     }
-    std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
-        "failed to create symlink {:?} for {:?}",
-        link.as_ref().display(),
-        original.as_ref().display(),
-    ));
+    if original.as_ref().is_file() {
+        std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
+            "failed to create symlink {:?} for {:?}",
+            link.as_ref().display(),
+            original.as_ref().display(),
+        ));
+    } else {
+        std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()).expect(&format!(
+            "failed to create symlink {:?} for {:?}",
+            link.as_ref().display(),
+            original.as_ref().display(),
+        ));
+    }
 }
 
 /// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
@@ -41,6 +49,8 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
             let ty = entry.file_type()?;
             if ty.is_dir() {
                 copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
+            } else if ty.is_symlink() {
+                copy_symlink(entry.path(), dst.join(entry.file_name()))?;
             } else {
                 std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
             }
@@ -59,6 +69,12 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
     }
 }
 
+fn copy_symlink<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
+    let target_path = std::fs::read_link(from).unwrap();
+    create_symlink(target_path, to);
+    Ok(())
+}
+
 /// Helper for reading entries in a given directory.
 pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
     for entry in read_dir(dir) {
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 63c4c4d8863..a44dd00ad79 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -45,7 +45,7 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust
 
 // These rely on external dependencies.
 pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
-pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx};
+pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
 pub use clang::{clang, Clang};
 pub use htmldocck::htmldocck;
 pub use llvm::{
@@ -72,13 +72,14 @@ pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, targe
 
 /// Helpers for building names of output artifacts that are potentially target-specific.
 pub use artifact_names::{
-    bin_name, dynamic_lib_extension, dynamic_lib_name, rust_lib_name, static_lib_name,
+    bin_name, dynamic_lib_extension, dynamic_lib_name, msvc_import_dynamic_lib_name, rust_lib_name,
+    static_lib_name,
 };
 
 /// Path-related helpers.
 pub use path_helpers::{
-    cwd, filename_not_in_denylist, has_extension, has_prefix, has_suffix, not_contains, path,
-    shallow_find_files, source_root,
+    cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, has_suffix,
+    not_contains, path, shallow_find_files, source_root,
 };
 
 /// Helpers for scoped test execution where certain properties are attempted to be maintained.
diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs
index f37ea8dfef8..b788bc6ef30 100644
--- a/src/tools/run-make-support/src/path_helpers.rs
+++ b/src/tools/run-make-support/src/path_helpers.rs
@@ -3,6 +3,7 @@
 use std::path::{Path, PathBuf};
 
 use crate::env::env_var;
+use crate::rfs;
 
 /// Return the current working directory.
 ///
@@ -40,7 +41,7 @@ pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
     filter: F,
 ) -> Vec<PathBuf> {
     let mut matching_files = Vec::new();
-    for entry in std::fs::read_dir(path).unwrap() {
+    for entry in rfs::read_dir(path) {
         let entry = entry.expect("failed to read directory entry.");
         let path = entry.path();
 
@@ -78,3 +79,8 @@ pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool {
 pub fn has_suffix<P: AsRef<Path>>(path: P, suffix: &str) -> bool {
     path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix))
 }
+
+/// Returns true if the filename at `path` contains `needle`.
+pub fn filename_contains<P: AsRef<Path>>(path: P, needle: &str) -> bool {
+    path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(needle))
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index bd43a62341d..d76f5381871 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -27,6 +27,7 @@ macro_rules! from_bytes {
     ($ty:tt, $value:expr) => {
         ($ty::from_le_bytes(match ($value).try_into() {
             Ok(it) => it,
+            #[allow(unreachable_patterns)]
             Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())),
         }))
     };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 057f5533805..9aa2eeebc17 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -1161,6 +1161,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                                     ProjectionElem::OpaqueCast(it) => {
                                         ProjectionElem::OpaqueCast(it)
                                     }
+                                    #[allow(unreachable_patterns)]
                                     ProjectionElem::Index(it) => match it {},
                                 })
                                 .collect(),
diff --git a/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs b/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
index 9257b8a4be6..b9adc67221a 100644
--- a/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
+++ b/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
@@ -34,15 +34,6 @@ pub fn check_for(x: Feature) -> bool {
 fn detect_features() -> cache::Initializer {
     let mut value = cache::Initializer::default();
 
-    // If the x86 CPU does not support the CPUID instruction then it is too
-    // old to support any of the currently-detectable features.
-    if !has_cpuid() {
-        return value;
-    }
-
-    // Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU
-    // has `cpuid` support.
-
     // 0. EAX = 0: Basic Information:
     // - EAX returns the "Highest Function Parameter", that is, the maximum
     // leaf value for subsequent calls of `cpuinfo` in range [0,
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
index 2e228aa3745..944b51615f8 100644
--- a/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
@@ -34,15 +34,6 @@ pub fn check_for(x: Feature) -> bool {
 fn detect_features() -> cache::Initializer {
     let mut value = cache::Initializer::default();
 
-    // If the x86 CPU does not support the CPUID instruction then it is too
-    // old to support any of the currently-detectable features.
-    if !has_cpuid() {
-        return value;
-    }
-
-    // Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU
-    // has `cpuid` support.
-
     // 0. EAX = 0: Basic Information:
     // - EAX returns the "Highest Function Parameter", that is, the maximum
     // leaf value for subsequent calls of `cpuinfo` in range [0,
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index bd4f54d22da..14f0a9cd23d 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,9 +1,5 @@
 run-make/branch-protection-check-IBT/Makefile
 run-make/cat-and-grep-sanity-check/Makefile
-run-make/cdylib-dylib-linkage/Makefile
-run-make/cross-lang-lto-clang/Makefile
-run-make/cross-lang-lto-pgo-smoketest/Makefile
-run-make/cross-lang-lto-upstream-rlibs/Makefile
 run-make/dep-info-doesnt-run-much/Makefile
 run-make/dep-info-spaces/Makefile
 run-make/dep-info/Makefile
@@ -11,38 +7,20 @@ run-make/emit-to-stdout/Makefile
 run-make/extern-fn-reachable/Makefile
 run-make/incr-add-rust-src-component/Makefile
 run-make/issue-84395-lto-embed-bitcode/Makefile
-run-make/issue-88756-default-output/Makefile
 run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/libtest-json/Makefile
 run-make/libtest-junit/Makefile
 run-make/libtest-thread-limit/Makefile
-run-make/link-cfg/Makefile
-run-make/long-linker-command-lines-cmd-exe/Makefile
-run-make/long-linker-command-lines/Makefile
 run-make/macos-deployment-target/Makefile
 run-make/min-global-align/Makefile
 run-make/native-link-modifier-bundle/Makefile
 run-make/no-alloc-shim/Makefile
-run-make/pdb-buildinfo-cl-cmd/Makefile
-run-make/pgo-gen-lto/Makefile
-run-make/pgo-indirect-call-promotion/Makefile
-run-make/print-calling-conventions/Makefile
-run-make/print-target-list/Makefile
-run-make/raw-dylib-alt-calling-convention/Makefile
-run-make/raw-dylib-c/Makefile
-run-make/redundant-libs/Makefile
 run-make/remap-path-prefix-dwarf/Makefile
-run-make/reproducible-build-2/Makefile
 run-make/reproducible-build/Makefile
 run-make/rlib-format-packed-bundled-libs/Makefile
-run-make/simd-ffi/Makefile
 run-make/split-debuginfo/Makefile
-run-make/stable-symbol-names/Makefile
-run-make/staticlib-dylib-linkage/Makefile
 run-make/symbol-mangling-hashed/Makefile
 run-make/sysroot-crates-are-unstable/Makefile
-run-make/thumb-none-cortex-m/Makefile
-run-make/thumb-none-qemu/Makefile
 run-make/translation/Makefile
 run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index de59d7d89f9..89011bbb48f 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -54,6 +54,7 @@ type ExceptionList = &'static [(&'static str, &'static str)];
 pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, &[&str])] = &[
     // The root workspace has to be first for check_rustfix to work.
     (".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES)), &[]),
+    ("library", EXCEPTIONS_STDLIB, Some((&["sysroot"], PERMITTED_STDLIB_DEPENDENCIES)), &[]),
     // Outside of the alphabetical section because rustfmt formats it using multiple lines.
     (
         "compiler/rustc_codegen_cranelift",
@@ -90,7 +91,6 @@ const EXCEPTIONS: ExceptionList = &[
     ("colored", "MPL-2.0"),                                  // rustfmt
     ("dissimilar", "Apache-2.0"),                            // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
     ("fluent-langneg", "Apache-2.0"),                        // rustc (fluent translations)
-    ("fortanix-sgx-abi", "MPL-2.0"),                         // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above.
     ("instant", "BSD-3-Clause"),                             // rustc_driver/tracing-subscriber/parking_lot
     ("mdbook", "MPL-2.0"),                                   // mdbook
     ("option-ext", "MPL-2.0"),                               // cargo-miri (via `directories`)
@@ -108,6 +108,17 @@ const EXCEPTIONS: ExceptionList = &[
     // tidy-alphabetical-end
 ];
 
+/// These are exceptions to Rust's permissive licensing policy, and
+/// should be considered bugs. Exceptions are only allowed in Rust
+/// tooling. It is _crucial_ that no exception crates be dependencies
+/// of the Rust runtime (std/test).
+#[rustfmt::skip]
+const EXCEPTIONS_STDLIB: ExceptionList = &[
+    // tidy-alphabetical-start
+    ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above.
+    // tidy-alphabetical-end
+];
+
 // FIXME uncomment once rust-lang/stdarch#1462 lands
 /*
 const EXCEPTIONS_STDARCH: ExceptionList = &[
@@ -181,6 +192,7 @@ const EXCEPTIONS_RUSTBOOK: ExceptionList = &[
 const EXCEPTIONS_CRANELIFT: ExceptionList = &[
     // tidy-alphabetical-start
     ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-bitset", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
@@ -228,10 +240,6 @@ const EXCEPTIONS_NON_STANDARD_LICENSE_DEPS: &[&str] = &[
     "ring",
 ];
 
-/// These are the root crates that are part of the runtime. The licenses for
-/// these and all their dependencies *must not* be in the exception list.
-const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"];
-
 const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
 
 /// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
@@ -240,7 +248,6 @@ const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
 /// rustc. Please check with the compiler team before adding an entry.
 const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
-    "addr2line",
     "adler",
     "ahash",
     "aho-corasick",
@@ -256,7 +263,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "cc",
     "cfg-if",
     "cfg_aliases",
-    "compiler_builtins",
     "cpufeatures",
     "crc32fast",
     "crossbeam-channel",
@@ -276,7 +282,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "digest",
     "displaydoc",
     "dissimilar",
-    "dlmalloc",
     "either",
     "elsa",
     "ena",
@@ -291,7 +296,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "fluent-langneg",
     "fluent-syntax",
     "fnv",
-    "fortanix-sgx-abi",
     "generic-array",
     "getopts",
     "getrandom",
@@ -354,12 +358,9 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "pulldown-cmark-escape",
     "punycode",
     "quote",
-    "r-efi",
-    "r-efi-alloc",
     "rand",
     "rand_chacha",
     "rand_core",
-    "rand_xorshift",
     "rand_xoshiro",
     "redox_syscall",
     "regex",
@@ -429,7 +430,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "unicode-security",
     "unicode-width",
     "unicode-xid",
-    "unwinding",
     "valuable",
     "version_check",
     "wasi",
@@ -463,6 +463,46 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-end
 ];
 
+const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
+    // tidy-alphabetical-start
+    "addr2line",
+    "adler",
+    "allocator-api2",
+    "cc",
+    "cfg-if",
+    "compiler_builtins",
+    "dlmalloc",
+    "fortanix-sgx-abi",
+    "getopts",
+    "gimli",
+    "hashbrown",
+    "hermit-abi",
+    "libc",
+    "memchr",
+    "miniz_oxide",
+    "object",
+    "r-efi",
+    "r-efi-alloc",
+    "rand",
+    "rand_core",
+    "rand_xorshift",
+    "rustc-demangle",
+    "unicode-width",
+    "unwinding",
+    "wasi",
+    "windows-sys",
+    "windows-targets",
+    "windows_aarch64_gnullvm",
+    "windows_aarch64_msvc",
+    "windows_i686_gnu",
+    "windows_i686_gnullvm",
+    "windows_i686_msvc",
+    "windows_x86_64_gnu",
+    "windows_x86_64_gnullvm",
+    "windows_x86_64_msvc",
+    // tidy-alphabetical-end
+];
+
 const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
     "ahash",
@@ -472,6 +512,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "bumpalo",
     "cfg-if",
     "cranelift-bforest",
+    "cranelift-bitset",
     "cranelift-codegen",
     "cranelift-codegen-meta",
     "cranelift-codegen-shared",
@@ -556,9 +597,8 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
             check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad);
         }
 
-        if workspace == "." {
-            let runtime_ids = compute_runtime_crates(&metadata);
-            check_runtime_license_exceptions(&metadata, runtime_ids, bad);
+        if workspace == "library" {
+            check_runtime_license_exceptions(&metadata, bad);
             checked_runtime_licenses = true;
         }
     }
@@ -583,16 +623,8 @@ pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool {
 ///
 /// Unlike for tools we don't allow exceptions to the `LICENSES` list for the runtime with the sole
 /// exception of `fortanix-sgx-abi` which is only used on x86_64-fortanix-unknown-sgx.
-fn check_runtime_license_exceptions(
-    metadata: &Metadata,
-    runtime_ids: HashSet<&PackageId>,
-    bad: &mut bool,
-) {
+fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) {
     for pkg in &metadata.packages {
-        if !runtime_ids.contains(&pkg.id) {
-            // Only checking dependencies of runtime libraries here.
-            continue;
-        }
         if pkg.source.is_none() {
             // No need to check local packages.
             continue;
@@ -613,20 +645,6 @@ fn check_runtime_license_exceptions(
                 continue;
             }
 
-            // This exception is due to the fact that the feature set of the
-            // `object` crate is different between rustc and libstd. In the
-            // standard library only a conservative set of features are enabled
-            // which notably does not include the `wasm` feature which pulls in
-            // this dependency. In the compiler, however, the `wasm` feature is
-            // enabled. This exception is intended to be here so long as the
-            // `EXCEPTIONS` above contains `wasmparser`, but once that goes away
-            // this can be removed.
-            if pkg.name == "wasmparser"
-                && pkg.license.as_deref() == Some("Apache-2.0 WITH LLVM-exception")
-            {
-                continue;
-            }
-
             tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id);
         }
     }
@@ -758,16 +776,6 @@ fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package {
     metadata.packages.iter().find(|p| &p.id == id).unwrap()
 }
 
-/// Finds all the packages that are in the rust runtime.
-fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> {
-    let mut result = HashSet::new();
-    for name in RUNTIME_CRATES {
-        let id = &pkg_from_name(metadata, name).id;
-        deps_of(metadata, id, &mut result);
-    }
-    result
-}
-
 /// Recursively find all dependencies.
 fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId, result: &mut HashSet<&'a PackageId>) {
     if !result.insert(pkg_id) {
diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs
index d658fe13d36..6a58d58dbde 100644
--- a/src/tools/tidy/src/edition.rs
+++ b/src/tools/tidy/src/edition.rs
@@ -4,11 +4,6 @@ use std::path::Path;
 
 use crate::walk::{filter_dirs, walk};
 
-fn is_edition_2021(mut line: &str) -> bool {
-    line = line.trim();
-    line == "edition = \"2021\""
-}
-
 pub fn check(path: &Path, bad: &mut bool) {
     walk(path, |path, _is_dir| filter_dirs(path), &mut |entry, contents| {
         let file = entry.path();
@@ -17,8 +12,15 @@ pub fn check(path: &Path, bad: &mut bool) {
             return;
         }
 
-        let is_2021 = contents.lines().any(is_edition_2021);
-        if !is_2021 {
+        let is_2021 = contents.lines().any(|line| line.trim() == "edition = \"2021\"");
+
+        let is_workspace = contents.lines().any(|line| line.trim() == "[workspace]");
+        let is_package = contents.lines().any(|line| line.trim() == "[package]");
+        assert!(is_workspace || is_package);
+
+        // Check that all packages use the 2021 edition. Virtual workspaces don't allow setting an
+        // edition, so these shouldn't be checked.
+        if is_package && !is_2021 {
             tidy_error!(
                 bad,
                 "{} doesn't have `edition = \"2021\"` on a separate line",
diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs
index c4a2c1ad44e..f9ebf53dddc 100644
--- a/tests/assembly/x86-return-float.rs
+++ b/tests/assembly/x86-return-float.rs
@@ -8,9 +8,9 @@
 // Force frame pointers to make ASM more consistent between targets
 //@ compile-flags: -O -C force-frame-pointers
 //@ filecheck-flags: --implicit-check-not fld --implicit-check-not fst
-//@ revisions: unix windows
-//@[unix] ignore-windows
-//@[windows] only-windows
+//@ revisions: normal win
+//@[normal] ignore-windows
+//@[win] only-windows
 
 #![crate_type = "lib"]
 #![feature(f16, f128)]
@@ -190,10 +190,10 @@ pub unsafe fn call_f64_f64(x: &mut (f64, f64)) {
     }
     // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
     // CHECK: calll {{()|_}}get_f64_f64
-    // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
-    // unix-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
-    // windows: movsd (%esp), %[[VAL1:.*]]
-    // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]]
+    // normal: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
+    // normal-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // win: movsd (%esp), %[[VAL1:.*]]
+    // win-NEXT: movsd 8(%esp), %[[VAL2:.*]]
     // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
     // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
     *x = get_f64_f64();
@@ -207,13 +207,13 @@ pub unsafe fn call_f32_f64(x: &mut (f32, f64)) {
     }
     // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
     // CHECK: calll {{()|_}}get_f32_f64
-    // unix: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
-    // unix-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
-    // windows: movss (%esp), %[[VAL1:.*]]
-    // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]]
+    // normal: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
+    // normal-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
+    // win: movss (%esp), %[[VAL1:.*]]
+    // win-NEXT: movsd 8(%esp), %[[VAL2:.*]]
     // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]])
-    // unix-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
-    // windows-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
+    // normal-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
+    // win-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
     *x = get_f32_f64();
 }
 
@@ -225,10 +225,10 @@ pub unsafe fn call_f64_f32(x: &mut (f64, f32)) {
     }
     // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
     // CHECK: calll {{()|_}}get_f64_f32
-    // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
-    // unix-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
-    // windows: movsd (%esp), %[[VAL1:.*]]
-    // windows-NEXT: movss 8(%esp), %[[VAL2:.*]]
+    // normal: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
+    // normal-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // win: movsd (%esp), %[[VAL1:.*]]
+    // win-NEXT: movss 8(%esp), %[[VAL2:.*]]
     // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
     // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]])
     *x = get_f64_f32();
@@ -257,10 +257,10 @@ pub unsafe fn call_f64_other(x: &mut (f64, usize)) {
     }
     // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
     // CHECK: calll {{()|_}}get_f64_other
-    // unix: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
-    // unix-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
-    // windows: movsd (%esp), %[[VAL1:.*]]
-    // windows-NEXT: movl 8(%esp), %[[VAL2:.*]]
+    // normal: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
+    // normal-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // win: movsd (%esp), %[[VAL1:.*]]
+    // win-NEXT: movl 8(%esp), %[[VAL2:.*]]
     // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
     // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]])
     *x = get_f64_other();
@@ -289,13 +289,13 @@ pub unsafe fn call_other_f64(x: &mut (usize, f64)) {
     }
     // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
     // CHECK: calll {{()|_}}get_other_f64
-    // unix: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
-    // unix-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
-    // windows: movl (%esp), %[[VAL1:.*]]
-    // windows-NEXT: movsd 8(%esp), %[[VAL2:.*]]
+    // normal: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
+    // normal-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
+    // win: movl (%esp), %[[VAL1:.*]]
+    // win-NEXT: movsd 8(%esp), %[[VAL2:.*]]
     // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]])
-    // unix-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
-    // windows-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
+    // normal-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
+    // win-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
     *x = get_other_f64();
 }
 
diff --git a/tests/codegen-units/item-collection/generic-impl.rs b/tests/codegen-units/item-collection/generic-impl.rs
index b4cd99272b1..23d09e0d8af 100644
--- a/tests/codegen-units/item-collection/generic-impl.rs
+++ b/tests/codegen-units/item-collection/generic-impl.rs
@@ -22,16 +22,16 @@ impl<T> Struct<T> {
     }
 }
 
-pub struct _LifeTimeOnly<'a> {
+pub struct LifeTimeOnly<'a> {
     _a: &'a u32,
 }
 
-impl<'a> _LifeTimeOnly<'a> {
-    //~ MONO_ITEM fn _LifeTimeOnly::<'_>::foo
+impl<'a> LifeTimeOnly<'a> {
+    //~ MONO_ITEM fn LifeTimeOnly::<'_>::foo
     pub fn foo(&self) {}
-    //~ MONO_ITEM fn _LifeTimeOnly::<'_>::bar
+    //~ MONO_ITEM fn LifeTimeOnly::<'_>::bar
     pub fn bar(&'a self) {}
-    //~ MONO_ITEM fn _LifeTimeOnly::<'_>::baz
+    //~ MONO_ITEM fn LifeTimeOnly::<'_>::baz
     pub fn baz<'b>(&'b self) {}
 
     pub fn non_instantiated<T>(&self) {}
diff --git a/tests/codegen-units/item-collection/overloaded-operators.rs b/tests/codegen-units/item-collection/overloaded-operators.rs
index e00e22dbab9..69b55695d3d 100644
--- a/tests/codegen-units/item-collection/overloaded-operators.rs
+++ b/tests/codegen-units/item-collection/overloaded-operators.rs
@@ -5,44 +5,44 @@
 
 use std::ops::{Add, Deref, Index, IndexMut};
 
-pub struct _Indexable {
+pub struct Indexable {
     data: [u8; 3],
 }
 
-impl Index<usize> for _Indexable {
+impl Index<usize> for Indexable {
     type Output = u8;
 
-    //~ MONO_ITEM fn <_Indexable as std::ops::Index<usize>>::index
+    //~ MONO_ITEM fn <Indexable as std::ops::Index<usize>>::index
     fn index(&self, index: usize) -> &Self::Output {
         if index >= 3 { &self.data[0] } else { &self.data[index] }
     }
 }
 
-impl IndexMut<usize> for _Indexable {
-    //~ MONO_ITEM fn <_Indexable as std::ops::IndexMut<usize>>::index_mut
+impl IndexMut<usize> for Indexable {
+    //~ MONO_ITEM fn <Indexable as std::ops::IndexMut<usize>>::index_mut
     fn index_mut(&mut self, index: usize) -> &mut Self::Output {
         if index >= 3 { &mut self.data[0] } else { &mut self.data[index] }
     }
 }
 
-//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::eq
-//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::ne
+//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::eq
+//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::ne
 #[derive(PartialEq)]
-pub struct _Equatable(u32);
+pub struct Equatable(u32);
 
-impl Add<u32> for _Equatable {
+impl Add<u32> for Equatable {
     type Output = u32;
 
-    //~ MONO_ITEM fn <_Equatable as std::ops::Add<u32>>::add
+    //~ MONO_ITEM fn <Equatable as std::ops::Add<u32>>::add
     fn add(self, rhs: u32) -> u32 {
         self.0 + rhs
     }
 }
 
-impl Deref for _Equatable {
+impl Deref for Equatable {
     type Target = u32;
 
-    //~ MONO_ITEM fn <_Equatable as std::ops::Deref>::deref
+    //~ MONO_ITEM fn <Equatable as std::ops::Deref>::deref
     fn deref(&self) -> &Self::Target {
         &self.0
     }
diff --git a/tests/codegen/aarch64-struct-align-128.rs b/tests/codegen/aarch64-struct-align-128.rs
index d1b4132d501..3fed19d96b1 100644
--- a/tests/codegen/aarch64-struct-align-128.rs
+++ b/tests/codegen/aarch64-struct-align-128.rs
@@ -1,12 +1,12 @@
 // Test that structs aligned to 128 bits are passed with the correct ABI on aarch64.
 
-//@ revisions:linux darwin windows
+//@ revisions: linux darwin win
 //@[linux] compile-flags: --target aarch64-unknown-linux-gnu
 //@[darwin] compile-flags: --target aarch64-apple-darwin
-//@[windows] compile-flags: --target aarch64-pc-windows-msvc
+//@[win] compile-flags: --target aarch64-pc-windows-msvc
 //@[linux] needs-llvm-components: aarch64
 //@[darwin] needs-llvm-components: aarch64
-//@[windows] needs-llvm-components: aarch64
+//@[win] needs-llvm-components: aarch64
 
 #![feature(no_core, lang_items)]
 #![crate_type = "lib"]
@@ -39,9 +39,9 @@ pub struct Wrapped8 {
 }
 
 extern "C" {
-    // linux:   declare void @test_8([2 x i64], [2 x i64], [2 x i64])
-    // darwin:  declare void @test_8([2 x i64], [2 x i64], [2 x i64])
-    // windows: declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    // linux:  declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    // darwin: declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    // win:    declare void @test_8([2 x i64], [2 x i64], [2 x i64])
     fn test_8(a: Align8, b: Transparent8, c: Wrapped8);
 }
 
@@ -69,9 +69,9 @@ pub struct Wrapped16 {
 }
 
 extern "C" {
-    // linux:   declare void @test_16([2 x i64], [2 x i64], i128)
-    // darwin:  declare void @test_16(i128, i128, i128)
-    // windows: declare void @test_16(i128, i128, i128)
+    // linux:  declare void @test_16([2 x i64], [2 x i64], i128)
+    // darwin: declare void @test_16(i128, i128, i128)
+    // win:    declare void @test_16(i128, i128, i128)
     fn test_16(a: Align16, b: Transparent16, c: Wrapped16);
 }
 
@@ -94,9 +94,9 @@ pub struct WrappedI128 {
 }
 
 extern "C" {
-    // linux:   declare void @test_i128(i128, i128, i128)
-    // darwin:  declare void @test_i128(i128, i128, i128)
-    // windows: declare void @test_i128(i128, i128, i128)
+    // linux:  declare void @test_i128(i128, i128, i128)
+    // darwin: declare void @test_i128(i128, i128, i128)
+    // win:    declare void @test_i128(i128, i128, i128)
     fn test_i128(a: I128, b: TransparentI128, c: WrappedI128);
 }
 
@@ -121,9 +121,9 @@ pub struct WrappedPacked {
 }
 
 extern "C" {
-    // linux:   declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
-    // darwin:  declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
-    // windows: declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    // linux:  declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    // darwin: declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    // win:    declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
     fn test_packed(a: Packed, b: TransparentPacked, c: WrappedPacked);
 }
 
diff --git a/tests/codegen/cold-call-declare-and-call.rs b/tests/codegen/cold-call-declare-and-call.rs
index cd41c0a6dfb..b18565ee6c3 100644
--- a/tests/codegen/cold-call-declare-and-call.rs
+++ b/tests/codegen/cold-call-declare-and-call.rs
@@ -1,8 +1,8 @@
-//@ revisions: NORMAL WINDOWS
+//@ revisions: NORMAL WIN
 //@ compile-flags: -C no-prepopulate-passes
 //@[NORMAL] ignore-windows
-//@[WINDOWS] only-windows
-//@[WINDOWS] only-x86_64
+//@[WIN] only-windows
+//@[WIN] only-x86_64
 
 #![crate_type = "lib"]
 #![feature(rust_cold_cc)]
@@ -14,8 +14,8 @@
 
 // See the comment in `Target::adjust_abi` for why this differs
 
-// WINDOWS: define void @this_should_never_happen(i16
-// WINDOWS: call void @this_should_never_happen(i16
+// WIN: define void @this_should_never_happen(i16
+// WIN: call void @this_should_never_happen(i16
 
 #[no_mangle]
 pub extern "rust-cold" fn this_should_never_happen(x: u16) {}
diff --git a/tests/codegen/default-requires-uwtable.rs b/tests/codegen/default-requires-uwtable.rs
index 567bd55ecc3..3cb35cea022 100644
--- a/tests/codegen/default-requires-uwtable.rs
+++ b/tests/codegen/default-requires-uwtable.rs
@@ -1,9 +1,9 @@
-//@ revisions: WINDOWS ANDROID
+//@ revisions: WINDOWS_ ANDROID_
 //@ compile-flags: -C panic=abort -Copt-level=0
-//@ [WINDOWS] compile-flags: --target=x86_64-pc-windows-msvc
-//@ [WINDOWS] needs-llvm-components: x86
-//@ [ANDROID] compile-flags: --target=armv7-linux-androideabi
-//@ [ANDROID] needs-llvm-components: arm
+//@ [WINDOWS_] compile-flags: --target=x86_64-pc-windows-msvc
+//@ [WINDOWS_] needs-llvm-components: x86
+//@ [ANDROID_] compile-flags: --target=armv7-linux-androideabi
+//@ [ANDROID_] needs-llvm-components: arm
 
 #![feature(no_core, lang_items)]
 #![crate_type = "lib"]
diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs
index eea4d9cb3cf..655fe779fca 100644
--- a/tests/codegen/instrument-coverage/testprog.rs
+++ b/tests/codegen/instrument-coverage/testprog.rs
@@ -1,7 +1,7 @@
 //@ edition: 2021
 //@ compile-flags: -Zno-profiler-runtime
 //@ compile-flags: -Cinstrument-coverage -Copt-level=0
-//@ revisions: LINUX DARWIN WINDOWS
+//@ revisions: LINUX DARWIN WIN
 
 //@ [LINUX] only-linux
 //@ [LINUX] filecheck-flags: -DINSTR_PROF_DATA=__llvm_prf_data
@@ -19,13 +19,13 @@
 //@ [DARWIN] filecheck-flags: -DINSTR_PROF_COVFUN=__LLVM_COV,__llvm_covfun
 //@ [DARWIN] filecheck-flags: -DCOMDAT_IF_SUPPORTED=
 
-//@ [WINDOWS] only-windows
-//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_DATA=.lprfd$M
-//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_NAME=.lprfn$M
-//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_CNTS=.lprfc$M
-//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_COVMAP=.lcovmap$M
-//@ [WINDOWS] filecheck-flags: -DINSTR_PROF_COVFUN=.lcovfun$M
-//@ [WINDOWS] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
+//@ [WIN] only-windows
+//@ [WIN] filecheck-flags: -DINSTR_PROF_DATA=.lprfd$M
+//@ [WIN] filecheck-flags: -DINSTR_PROF_NAME=.lprfn$M
+//@ [WIN] filecheck-flags: -DINSTR_PROF_CNTS=.lprfc$M
+//@ [WIN] filecheck-flags: -DINSTR_PROF_COVMAP=.lcovmap$M
+//@ [WIN] filecheck-flags: -DINSTR_PROF_COVFUN=.lcovfun$M
+//@ [WIN] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
 
 // ignore-tidy-linelength
 
@@ -71,7 +71,7 @@ fn main() {
 // Check for metadata, variables, declarations, and function definitions injected
 // into LLVM IR when compiling with -Cinstrument-coverage.
 
-// WINDOWS:      $__llvm_profile_runtime_user = comdat any
+// WIN:          $__llvm_profile_runtime_user = comdat any
 
 // CHECK:        @__llvm_coverage_mapping = private constant
 // CHECK-SAME:   section "[[INSTR_PROF_COVMAP]]", align 8
@@ -79,7 +79,7 @@ fn main() {
 // CHECK:        @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant
 // CHECK-SAME:   section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
 
-// WINDOWS:      @__llvm_profile_runtime = external{{.*}}global i32
+// WIN:          @__llvm_profile_runtime = external{{.*}}global i32
 
 // CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
 // CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
@@ -111,10 +111,10 @@ fn main() {
 
 // CHECK:        declare void @llvm.instrprof.increment(ptr, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]]
 
-// WINDOWS:      define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {
-// WINDOWS-NEXT: %1 = load i32, ptr @__llvm_profile_runtime
-// WINDOWS-NEXT: ret i32 %1
-// WINDOWS-NEXT: }
+// WIN:          define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat {
+// WIN-NEXT:     %1 = load i32, ptr @__llvm_profile_runtime
+// WIN-NEXT:     ret i32 %1
+// WIN-NEXT:     }
 
 // CHECK:        attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind }
-// WINDOWS:      attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline }
+// WIN:          attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline }
diff --git a/tests/codegen/issues/issue-107681-unwrap_unchecked.rs b/tests/codegen/issues/issue-107681-unwrap_unchecked.rs
new file mode 100644
index 00000000000..7d9679d2322
--- /dev/null
+++ b/tests/codegen/issues/issue-107681-unwrap_unchecked.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -O
+//@ min-llvm-version: 19
+
+// Test for #107681.
+// Make sure we don't create `br` or `select` instructions.
+
+#![crate_type = "lib"]
+
+use std::iter::Copied;
+use std::slice::Iter;
+
+#[no_mangle]
+pub unsafe fn foo(x: &mut Copied<Iter<'_, u32>>) -> u32 {
+    // CHECK-LABEL: @foo(
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+    // CHECK: [[RET:%.*]] = load i32, ptr
+    // CHECK-NEXT: ret i32 [[RET]]
+    x.next().unwrap_unchecked()
+}
diff --git a/tests/codegen/issues/issue-118306.rs b/tests/codegen/issues/issue-118306.rs
new file mode 100644
index 00000000000..8af1c6a971c
--- /dev/null
+++ b/tests/codegen/issues/issue-118306.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -O
+//@ min-llvm-version: 19
+//@ only-x86_64
+
+// Test for #118306.
+// Make sure we don't create `br` or `select` instructions.
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn branchy(input: u64) -> u64 {
+    // CHECK-LABEL: @branchy(
+    // CHECK-NEXT:  start:
+    // CHECK-NEXT:    [[_2:%.*]] = and i64 [[INPUT:%.*]], 3
+    // CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i64], ptr @switch.table.branchy, i64 0, i64 [[_2]]
+    // CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load i64, ptr [[SWITCH_GEP]]
+    // CHECK-NEXT:    ret i64 [[SWITCH_LOAD]]
+    match input % 4 {
+        1 | 2 => 1,
+        3 => 2,
+        _ => 0,
+    }
+}
diff --git a/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs
new file mode 100644
index 00000000000..4b520a62069
--- /dev/null
+++ b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -O
+//@ min-llvm-version: 19
+
+#![crate_type = "lib"]
+
+pub enum State {
+    A([u8; 753]),
+    B([u8; 753]),
+}
+
+// CHECK-LABEL: @update
+#[no_mangle]
+pub unsafe fn update(s: *mut State) {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: store i8
+    // CHECK-NEXT: ret
+    let State::A(v) = s.read() else { std::hint::unreachable_unchecked() };
+    s.write(State::B(v));
+}
diff --git a/tests/codegen/issues/issue-126585.rs b/tests/codegen/issues/issue-126585.rs
new file mode 100644
index 00000000000..a468efd728d
--- /dev/null
+++ b/tests/codegen/issues/issue-126585.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -Copt-level=s
+//@ min-llvm-version: 19
+//@ only-x86_64
+
+// Test for #126585.
+// Ensure that this IR doesn't have extra undef phi input, which also guarantees that this asm
+// doesn't have subsequent labels and unnecessary `jmp` instructions.
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+fn checked_div_round(a: u64, b: u64) -> Option<u64> {
+    // CHECK-LABEL: @checked_div_round
+    // CHECK: phi
+    // CHECK-NOT: undef
+    // CHECK: phi
+    // CHECK-NOT: undef
+    match b {
+        0 => None,
+        1 => Some(a),
+        // `a / b` is computable and `(a % b) * 2` can not overflow since `b >= 2`.
+        b => Some(a / b + if (a % b) * 2 >= b { 1 } else { 0 }),
+    }
+}
diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs
index 31020b77984..7de224b92d8 100644
--- a/tests/codegen/iter-repeat-n-trivial-drop.rs
+++ b/tests/codegen/iter-repeat-n-trivial-drop.rs
@@ -1,8 +1,9 @@
-//@ compile-flags: -O
+//@ compile-flags: -C opt-level=3
 //@ only-x86_64
 
 #![crate_type = "lib"]
 #![feature(iter_repeat_n)]
+#![feature(array_repeat)]
 
 #[derive(Clone)]
 pub struct NotCopy(u16);
@@ -54,3 +55,15 @@ pub fn vec_extend_via_iter_repeat_n() -> Vec<u8> {
     v.extend(std::iter::repeat_n(42_u8, n));
     v
 }
+
+// Array repeat uses `RepeatN::next_unchecked` internally,
+// so also check that the distinction disappears there.
+
+#[no_mangle]
+// CHECK-LABEL: @array_repeat_not_copy
+pub unsafe fn array_repeat_not_copy(item: NotCopy) -> [NotCopy; 8] {
+    // CHECK: insertelement {{.+}} i16 %item
+    // CHECK: shufflevector <8 x i16> {{.+}} zeroinitializer
+    // CHECK: store <8 x i16>
+    std::array::repeat(item)
+}
diff --git a/tests/codegen/repr/transparent-sysv64.rs b/tests/codegen/repr/transparent-sysv64.rs
index afb06dcc1bd..068414976c5 100644
--- a/tests/codegen/repr/transparent-sysv64.rs
+++ b/tests/codegen/repr/transparent-sysv64.rs
@@ -1,12 +1,12 @@
-//@ revisions: linux apple windows
+//@ revisions: linux apple win
 //@ compile-flags: -O -C no-prepopulate-passes
 
 //@[linux] compile-flags: --target x86_64-unknown-linux-gnu
 //@[linux] needs-llvm-components: x86
 //@[apple] compile-flags: --target x86_64-apple-darwin
 //@[apple] needs-llvm-components: x86
-//@[windows] compile-flags: --target x86_64-pc-windows-msvc
-//@[windows] needs-llvm-components: x86
+//@[win] compile-flags: --target x86_64-pc-windows-msvc
+//@[win] needs-llvm-components: x86
 
 #![feature(no_core, lang_items)]
 #![crate_type = "lib"]
diff --git a/tests/codegen/simd/issue-120720-reduce-nan.rs b/tests/codegen/simd/issue-120720-reduce-nan.rs
deleted file mode 100644
index 13af0bb076e..00000000000
--- a/tests/codegen/simd/issue-120720-reduce-nan.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-//@ compile-flags: -C opt-level=3 -C target-cpu=cannonlake
-//@ only-x86_64
-
-// In a previous implementation, _mm512_reduce_add_pd did the reduction with all fast-math flags
-// enabled, making it UB to reduce a vector containing a NaN.
-
-#![crate_type = "lib"]
-#![feature(stdarch_x86_avx512, avx512_target_feature)]
-use std::arch::x86_64::*;
-
-// CHECK-LABEL: @demo(
-#[no_mangle]
-#[target_feature(enable = "avx512f")] // Function-level target feature mismatches inhibit inlining
-pub unsafe fn demo() -> bool {
-    // CHECK: %0 = tail call reassoc double @llvm.vector.reduce.fadd.v8f64(
-    // CHECK: %_0.i = fcmp uno double %0, 0.000000e+00
-    // CHECK: ret i1 %_0.i
-    let res =
-        unsafe { _mm512_reduce_add_pd(_mm512_set_pd(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, f64::NAN)) };
-    res.is_nan()
-}
diff --git a/tests/codegen/sse42-implies-crc32.rs b/tests/codegen/sse42-implies-crc32.rs
index 94fcd77bc88..8a9c496a3a5 100644
--- a/tests/codegen/sse42-implies-crc32.rs
+++ b/tests/codegen/sse42-implies-crc32.rs
@@ -12,4 +12,4 @@ pub unsafe fn crc32sse(v: u8) -> u32 {
     _mm_crc32_u8(out, v)
 }
 
-// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32"}}
+// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32.*"}}
diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs
index 1e2c364dbbc..f38a1ae72de 100644
--- a/tests/codegen/target-feature-overrides.rs
+++ b/tests/codegen/target-feature-overrides.rs
@@ -1,7 +1,7 @@
 //@ revisions: COMPAT INCOMPAT
 //@ needs-llvm-components: x86
 //@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3
-//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2,+avx
+//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2
 //@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx
 
 // See also tests/assembly/target-feature-multiple.rs
@@ -39,8 +39,8 @@ pub unsafe fn banana() -> u32 {
 }
 
 // CHECK: attributes [[APPLEATTRS]]
-// COMPAT-SAME: "target-features"="+avx2,+avx,+avx"
-// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx"
+// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
 // CHECK: attributes [[BANANAATTRS]]
-// COMPAT-SAME: "target-features"="+avx2,+avx"
+// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
 // INCOMPAT-SAME: "target-features"="-avx2,-avx"
diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs
index 7f0805bc1b4..1b4596ae2cb 100644
--- a/tests/codegen/tied-features-strength.rs
+++ b/tests/codegen/tied-features-strength.rs
@@ -8,7 +8,7 @@
 // is LLVM-14 we can remove the optional regex matching for this feature.
 
 //@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0
-// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+sve,?)|(\+neon,?))*}}" }
+// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
 
 //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
 // DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-sve,?)|(\+neon,?))*}}" }
diff --git a/tests/crashes/121127.rs b/tests/crashes/121127.rs
index 2e64bf68b82..e50dc7763fc 100644
--- a/tests/crashes/121127.rs
+++ b/tests/crashes/121127.rs
@@ -1,5 +1,5 @@
 //@ known-bug: #121127
-//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes -C debuginfo=2
+//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes -C debuginfo=2
 // Note that as of PR#123949 this only crashes with debuginfo enabled
 
 #![feature(specialization)]
diff --git a/tests/crashes/122909.rs b/tests/crashes/122909.rs
deleted file mode 100644
index 90bba772b91..00000000000
--- a/tests/crashes/122909.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes
-//@ known-bug: #122909
-
-
-use std::sync::{Arc, Context, Weak};
-
-pub struct WeakOnce<T>();
-impl<T> WeakOnce<T> {
-    extern "rust-call" fn try_get(&self) -> Option<Arc<T>> {}
-
-    pub fn get(&self) -> Arc<T> {
-        self.try_get()
-            .unwrap_or_else(|| panic!("Singleton {} not available", std::any::type_name::<T>()))
-    }
-}
diff --git a/tests/crashes/126272.rs b/tests/crashes/126272.rs
deleted file mode 100644
index 3412c7d8f0f..00000000000
--- a/tests/crashes/126272.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//@ known-bug: rust-lang/rust#126272
-
-#![feature(adt_const_params)]
-#![allow(incomplete_features)]
-
-use std::marker::ConstParamTy;
-
-#[derive(Debug, PartialEq, Eq, ConstParamTy)]
-struct Foo {
-    value: i32,
-    nested: &'static Bar<std::fmt::Debug>,
-}
-
-#[derive(Debug, PartialEq, Eq, ConstParamTy)]
-struct Bar<T>(T);
-
-struct Test<const F: Foo>;
-
-fn main() {
-    let x: Test<
-        {
-            Foo {
-                value: 3,
-                nested: &Bar(4),
-            }
-        },
-    > = Test;
-}
diff --git a/tests/crashes/126896.rs b/tests/crashes/126896.rs
index 35bf9d5207a..49c539d7acc 100644
--- a/tests/crashes/126896.rs
+++ b/tests/crashes/126896.rs
@@ -1,5 +1,5 @@
 //@ known-bug: rust-lang/rust#126896
-//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes
+//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes
 
 #![feature(type_alias_impl_trait)]
 type Two<'a, 'b> = impl std::fmt::Debug;
diff --git a/tests/crashes/127299.rs b/tests/crashes/127299.rs
deleted file mode 100644
index 7eb78387997..00000000000
--- a/tests/crashes/127299.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ known-bug: rust-lang/rust#127299
-trait Qux {
-    fn bar() -> i32;
-}
-
-pub struct Lint {
-    pub desc: &'static Qux,
-}
-
-static FOO: &Lint = &Lint { desc: "desc" };
-
-fn main() {}
diff --git a/tests/crashes/128094.rs b/tests/crashes/128094.rs
new file mode 100644
index 00000000000..105a1c84a65
--- /dev/null
+++ b/tests/crashes/128094.rs
@@ -0,0 +1,14 @@
+//@ known-bug: rust-lang/rust#128094
+//@ compile-flags: -Zmir-opt-level=5 --edition=2018
+
+pub enum Request {
+    TestSome(T),
+}
+
+pub async fn handle_event(event: Request) {
+    async move {
+        static instance: Request = Request { bar: 17 };
+        &instance
+    }
+    .await;
+}
diff --git a/tests/crashes/128176.rs b/tests/crashes/128176.rs
new file mode 100644
index 00000000000..70fada4f0fe
--- /dev/null
+++ b/tests/crashes/128176.rs
@@ -0,0 +1,13 @@
+//@ known-bug: rust-lang/rust#128176
+
+#![feature(generic_const_exprs)]
+#![feature(object_safe_for_dispatch)]
+trait X {
+    type Y<const N: i16>;
+}
+
+const _: () = {
+    fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
+};
+
+fn main() {}
diff --git a/tests/crashes/128190.rs b/tests/crashes/128190.rs
new file mode 100644
index 00000000000..0fa7027ae60
--- /dev/null
+++ b/tests/crashes/128190.rs
@@ -0,0 +1,7 @@
+//@ known-bug: rust-lang/rust#128190
+
+fn a(&self) {
+    15
+}
+
+reuse a as b {  struct S; }
diff --git a/tests/crashes/128327.rs b/tests/crashes/128327.rs
new file mode 100644
index 00000000000..a63f758c317
--- /dev/null
+++ b/tests/crashes/128327.rs
@@ -0,0 +1,5 @@
+//@ known-bug: rust-lang/rust#128327
+
+use std::ops::Deref;
+struct Apple((Apple, <&'static [f64] as Deref>::Target(Banana ? Citron)));
+fn main(){}
diff --git a/tests/crashes/128346.rs b/tests/crashes/128346.rs
new file mode 100644
index 00000000000..93d9c40a544
--- /dev/null
+++ b/tests/crashes/128346.rs
@@ -0,0 +1,13 @@
+//@ known-bug: rust-lang/rust#128346
+
+macro_rules! one_rep {
+    ( $($a:ident)* ) => {
+        A(
+            const ${concat($a, Z)}: i32 = 3;
+        )*
+    };
+}
+
+fn main() {
+    one_rep!(A B C);
+}
diff --git a/tests/debuginfo/thread-names.rs b/tests/debuginfo/thread-names.rs
index 1b9ada6fc52..6b3b0c7f4b2 100644
--- a/tests/debuginfo/thread-names.rs
+++ b/tests/debuginfo/thread-names.rs
@@ -1,8 +1,8 @@
 //@ compile-flags:-g
-//@ revisions: macos windows
+//@ revisions: macos win
 // We can't set the main thread name on Linux because it renames the process (#97191)
 //@[macos] only-macos
-//@[windows] only-windows
+//@[win] only-windows
 //@ ignore-sgx
 //@ ignore-windows-gnu
 
diff --git a/tests/mir-opt/building/custom/terminators.rs b/tests/mir-opt/building/custom/terminators.rs
index a8e0b4b35bf..ed08040a2a5 100644
--- a/tests/mir-opt/building/custom/terminators.rs
+++ b/tests/mir-opt/building/custom/terminators.rs
@@ -22,6 +22,18 @@ fn direct_call(x: i32) -> i32 {
     }
 }
 
+// EMIT_MIR terminators.tail_call.built.after.mir
+#[custom_mir(dialect = "built")]
+fn tail_call(x: i32) -> i32 {
+    mir! {
+        let y;
+        {
+            y = x + 42;
+            TailCall(ident(y))
+        }
+    }
+}
+
 // EMIT_MIR terminators.indirect_call.built.after.mir
 #[custom_mir(dialect = "built")]
 fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 {
diff --git a/tests/mir-opt/building/custom/terminators.tail_call.built.after.mir b/tests/mir-opt/building/custom/terminators.tail_call.built.after.mir
new file mode 100644
index 00000000000..4cf6e459aa8
--- /dev/null
+++ b/tests/mir-opt/building/custom/terminators.tail_call.built.after.mir
@@ -0,0 +1,11 @@
+// MIR for `tail_call` after built
+
+fn tail_call(_1: i32) -> i32 {
+    let mut _0: i32;
+    let mut _2: i32;
+
+    bb0: {
+        _2 = Add(_1, const 42_i32);
+        tailcall ident::<i32>(Spanned { node: _2, span: $DIR/terminators.rs:32:28: 32:29 (#0) });
+    }
+}
diff --git a/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir
index 78356a90743..bba4d9c0149 100644
--- a/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir
@@ -13,17 +13,17 @@ fn opt1(_1: &Result<u32, Void>) -> &u32 {
 
     bb0: {
         PlaceMention(_1);
-        _2 = discriminant((*_1));
-        switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
+        falseEdge -> [real: bb4, imaginary: bb1];
     }
 
     bb1: {
-        FakeRead(ForMatchedPlace(None), _1);
-        unreachable;
+        _2 = discriminant((*_1));
+        switchInt(move _2) -> [1: bb3, otherwise: bb2];
     }
 
     bb2: {
-        falseEdge -> [real: bb4, imaginary: bb3];
+        FakeRead(ForMatchedPlace(None), _1);
+        unreachable;
     }
 
     bb3: {
diff --git a/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir
index 979fbb2860d..fc0769d6f7d 100644
--- a/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir
@@ -11,25 +11,10 @@ fn opt2(_1: &Result<u32, Void>) -> &u32 {
 
     bb0: {
         PlaceMention(_1);
-        _2 = discriminant((*_1));
-        switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
-    }
-
-    bb1: {
-        FakeRead(ForMatchedPlace(None), _1);
-        unreachable;
-    }
-
-    bb2: {
         StorageLive(_3);
         _3 = &(((*_1) as Ok).0: u32);
         _0 = &(*_3);
         StorageDead(_3);
         return;
     }
-
-    bb3: {
-        FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void));
-        unreachable;
-    }
 }
diff --git a/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir
index 93ebe600b3f..86347db4d92 100644
--- a/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir
@@ -12,24 +12,19 @@ fn opt3(_1: &Result<u32, Void>) -> &u32 {
     bb0: {
         PlaceMention(_1);
         _2 = discriminant((*_1));
-        switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
+        switchInt(move _2) -> [1: bb2, otherwise: bb1];
     }
 
     bb1: {
-        FakeRead(ForMatchedPlace(None), _1);
-        unreachable;
-    }
-
-    bb2: {
-        FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void));
-        unreachable;
-    }
-
-    bb3: {
         StorageLive(_3);
         _3 = &(((*_1) as Ok).0: u32);
         _0 = &(*_3);
         StorageDead(_3);
         return;
     }
+
+    bb2: {
+        FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void));
+        unreachable;
+    }
 }
diff --git a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff
index dc50ae95472..fc34ce7125e 100644
--- a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff
+++ b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff
@@ -5,37 +5,42 @@
       debug i => _1;
       let mut _0: u128;
       let mut _2: i128;
++     let mut _3: i128;
   
       bb0: {
           _2 = discriminant(_1);
-          switchInt(move _2) -> [1: bb5, 2: bb4, 3: bb3, 340282366920938463463374607431768211455: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const core::num::<impl u128>::MAX;
-          goto -> bb6;
-      }
-  
-      bb3: {
-          _0 = const 3_u128;
-          goto -> bb6;
-      }
-  
-      bb4: {
-          _0 = const 2_u128;
-          goto -> bb6;
-      }
-  
-      bb5: {
-          _0 = const 1_u128;
-          goto -> bb6;
-      }
-  
-      bb6: {
+-         switchInt(move _2) -> [1: bb5, 2: bb4, 3: bb3, 340282366920938463463374607431768211455: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const core::num::<impl u128>::MAX;
+-         goto -> bb6;
+-     }
+- 
+-     bb3: {
+-         _0 = const 3_u128;
+-         goto -> bb6;
+-     }
+- 
+-     bb4: {
+-         _0 = const 2_u128;
+-         goto -> bb6;
+-     }
+- 
+-     bb5: {
+-         _0 = const 1_u128;
+-         goto -> bb6;
+-     }
+- 
+-     bb6: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u128 (IntToInt);
++         StorageDead(_3);
           return;
       }
   }
diff --git a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff
deleted file mode 100644
index 3514914b8ec..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,37 +0,0 @@
-- // MIR for `match_i16_i8` before MatchBranchSimplification
-+ // MIR for `match_i16_i8` after MatchBranchSimplification
-  
-  fn match_i16_i8(_1: EnumAi16) -> i8 {
-      debug i => _1;
-      let mut _0: i8;
-      let mut _2: i16;
-  
-      bb0: {
-          _2 = discriminant(_1);
-          switchInt(move _2) -> [65535: bb4, 2: bb3, 65533: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const -3_i8;
-          goto -> bb5;
-      }
-  
-      bb3: {
-          _0 = const 2_i8;
-          goto -> bb5;
-      }
-  
-      bb4: {
-          _0 = const -1_i8;
-          goto -> bb5;
-      }
-  
-      bb5: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff
deleted file mode 100644
index ff4255ec8cc..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,37 +0,0 @@
-- // MIR for `match_i8_i16` before MatchBranchSimplification
-+ // MIR for `match_i8_i16` after MatchBranchSimplification
-  
-  fn match_i8_i16(_1: EnumAi8) -> i16 {
-      debug i => _1;
-      let mut _0: i16;
-      let mut _2: i8;
-  
-      bb0: {
-          _2 = discriminant(_1);
-          switchInt(move _2) -> [255: bb4, 2: bb3, 253: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const -3_i16;
-          goto -> bb5;
-      }
-  
-      bb3: {
-          _0 = const 2_i16;
-          goto -> bb5;
-      }
-  
-      bb4: {
-          _0 = const -1_i16;
-          goto -> bb5;
-      }
-  
-      bb5: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff
deleted file mode 100644
index 022039ecee6..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,37 +0,0 @@
-- // MIR for `match_i8_i16_failed` before MatchBranchSimplification
-+ // MIR for `match_i8_i16_failed` after MatchBranchSimplification
-  
-  fn match_i8_i16_failed(_1: EnumAi8) -> i16 {
-      debug i => _1;
-      let mut _0: i16;
-      let mut _2: i8;
-  
-      bb0: {
-          _2 = discriminant(_1);
-          switchInt(move _2) -> [255: bb4, 2: bb3, 253: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const 3_i16;
-          goto -> bb5;
-      }
-  
-      bb3: {
-          _0 = const 2_i16;
-          goto -> bb5;
-      }
-  
-      bb4: {
-          _0 = const -1_i16;
-          goto -> bb5;
-      }
-  
-      bb5: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..7f8c2ab8d37
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff
@@ -0,0 +1,52 @@
+- // MIR for `match_sext_i8_i16` before MatchBranchSimplification
++ // MIR for `match_sext_i8_i16` after MatchBranchSimplification
+  
+  fn match_sext_i8_i16(_1: EnumAi8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+      let mut _2: i8;
++     let mut _3: i8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [128: bb6, 255: bb5, 0: bb4, 1: bb3, 127: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 127_i16;
+-         goto -> bb7;
+-     }
+- 
+-     bb3: {
+-         _0 = const 1_i16;
+-         goto -> bb7;
+-     }
+- 
+-     bb4: {
+-         _0 = const 0_i16;
+-         goto -> bb7;
+-     }
+- 
+-     bb5: {
+-         _0 = const -1_i16;
+-         goto -> bb7;
+-     }
+- 
+-     bb6: {
+-         _0 = const -128_i16;
+-         goto -> bb7;
+-     }
+- 
+-     bb7: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i16 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..94ec2293222
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff
@@ -0,0 +1,47 @@
+- // MIR for `match_sext_i8_i16_failed` before MatchBranchSimplification
++ // MIR for `match_sext_i8_i16_failed` after MatchBranchSimplification
+  
+  fn match_sext_i8_i16_failed(_1: EnumAi8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+      let mut _2: i8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [128: bb6, 255: bb5, 0: bb4, 1: bb3, 127: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 127_i16;
+          goto -> bb7;
+      }
+  
+      bb3: {
+          _0 = const 1_i16;
+          goto -> bb7;
+      }
+  
+      bb4: {
+          _0 = const 0_i16;
+          goto -> bb7;
+      }
+  
+      bb5: {
+          _0 = const 255_i16;
+          goto -> bb7;
+      }
+  
+      bb6: {
+          _0 = const -128_i16;
+          goto -> bb7;
+      }
+  
+      bb7: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..86d0d0ba6cf
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff
@@ -0,0 +1,52 @@
+- // MIR for `match_sext_i8_u16` before MatchBranchSimplification
++ // MIR for `match_sext_i8_u16` after MatchBranchSimplification
+  
+  fn match_sext_i8_u16(_1: EnumAi8) -> u16 {
+      debug i => _1;
+      let mut _0: u16;
+      let mut _2: i8;
++     let mut _3: i8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [128: bb6, 255: bb5, 0: bb4, 1: bb3, 127: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 127_u16;
+-         goto -> bb7;
+-     }
+- 
+-     bb3: {
+-         _0 = const 1_u16;
+-         goto -> bb7;
+-     }
+- 
+-     bb4: {
+-         _0 = const 0_u16;
+-         goto -> bb7;
+-     }
+- 
+-     bb5: {
+-         _0 = const u16::MAX;
+-         goto -> bb7;
+-     }
+- 
+-     bb6: {
+-         _0 = const 65408_u16;
+-         goto -> bb7;
+-     }
+- 
+-     bb7: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u16 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..281f373bf87
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff
@@ -0,0 +1,47 @@
+- // MIR for `match_sext_i8_u16_failed` before MatchBranchSimplification
++ // MIR for `match_sext_i8_u16_failed` after MatchBranchSimplification
+  
+  fn match_sext_i8_u16_failed(_1: EnumAi8) -> u16 {
+      debug i => _1;
+      let mut _0: u16;
+      let mut _2: i8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [128: bb6, 255: bb5, 0: bb4, 1: bb3, 127: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 127_u16;
+          goto -> bb7;
+      }
+  
+      bb3: {
+          _0 = const 1_u16;
+          goto -> bb7;
+      }
+  
+      bb4: {
+          _0 = const 0_u16;
+          goto -> bb7;
+      }
+  
+      bb5: {
+          _0 = const 255_u16;
+          goto -> bb7;
+      }
+  
+      bb6: {
+          _0 = const 65408_u16;
+          goto -> bb7;
+      }
+  
+      bb7: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..d3d27be2070
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff
@@ -0,0 +1,77 @@
+- // MIR for `match_trunc_i16_i8` before MatchBranchSimplification
++ // MIR for `match_trunc_i16_i8` after MatchBranchSimplification
+  
+  fn match_trunc_i16_i8(_1: EnumAi16) -> i8 {
+      debug i => _1;
+      let mut _0: i8;
+      let mut _2: i16;
++     let mut _3: i16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [128: bb11, 255: bb10, 0: bb9, 1: bb8, 127: bb7, 65408: bb6, 65535: bb5, 65280: bb4, 65281: bb3, 65407: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const i8::MAX;
+-         goto -> bb12;
+-     }
+- 
+-     bb3: {
+-         _0 = const 1_i8;
+-         goto -> bb12;
+-     }
+- 
+-     bb4: {
+-         _0 = const 0_i8;
+-         goto -> bb12;
+-     }
+- 
+-     bb5: {
+-         _0 = const -1_i8;
+-         goto -> bb12;
+-     }
+- 
+-     bb6: {
+-         _0 = const i8::MIN;
+-         goto -> bb12;
+-     }
+- 
+-     bb7: {
+-         _0 = const i8::MAX;
+-         goto -> bb12;
+-     }
+- 
+-     bb8: {
+-         _0 = const 1_i8;
+-         goto -> bb12;
+-     }
+- 
+-     bb9: {
+-         _0 = const 0_i8;
+-         goto -> bb12;
+-     }
+- 
+-     bb10: {
+-         _0 = const -1_i8;
+-         goto -> bb12;
+-     }
+- 
+-     bb11: {
+-         _0 = const i8::MIN;
+-         goto -> bb12;
+-     }
+- 
+-     bb12: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i8 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..7f663baefba
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff
@@ -0,0 +1,72 @@
+- // MIR for `match_trunc_i16_i8_failed` before MatchBranchSimplification
++ // MIR for `match_trunc_i16_i8_failed` after MatchBranchSimplification
+  
+  fn match_trunc_i16_i8_failed(_1: EnumAi16) -> i8 {
+      debug i => _1;
+      let mut _0: i8;
+      let mut _2: i16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [128: bb11, 255: bb10, 0: bb9, 1: bb8, 127: bb7, 65408: bb6, 65535: bb5, 65280: bb4, 65281: bb3, 65407: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const -127_i8;
+          goto -> bb12;
+      }
+  
+      bb3: {
+          _0 = const 1_i8;
+          goto -> bb12;
+      }
+  
+      bb4: {
+          _0 = const 0_i8;
+          goto -> bb12;
+      }
+  
+      bb5: {
+          _0 = const -1_i8;
+          goto -> bb12;
+      }
+  
+      bb6: {
+          _0 = const i8::MIN;
+          goto -> bb12;
+      }
+  
+      bb7: {
+          _0 = const i8::MAX;
+          goto -> bb12;
+      }
+  
+      bb8: {
+          _0 = const 1_i8;
+          goto -> bb12;
+      }
+  
+      bb9: {
+          _0 = const 0_i8;
+          goto -> bb12;
+      }
+  
+      bb10: {
+          _0 = const -1_i8;
+          goto -> bb12;
+      }
+  
+      bb11: {
+          _0 = const i8::MIN;
+          goto -> bb12;
+      }
+  
+      bb12: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..5fe899148eb
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff
@@ -0,0 +1,77 @@
+- // MIR for `match_trunc_i16_u8` before MatchBranchSimplification
++ // MIR for `match_trunc_i16_u8` after MatchBranchSimplification
+  
+  fn match_trunc_i16_u8(_1: EnumAi16) -> u8 {
+      debug i => _1;
+      let mut _0: u8;
+      let mut _2: i16;
++     let mut _3: i16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [128: bb11, 255: bb10, 0: bb9, 1: bb8, 127: bb7, 65408: bb6, 65535: bb5, 65280: bb4, 65281: bb3, 65407: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 127_u8;
+-         goto -> bb12;
+-     }
+- 
+-     bb3: {
+-         _0 = const 1_u8;
+-         goto -> bb12;
+-     }
+- 
+-     bb4: {
+-         _0 = const 0_u8;
+-         goto -> bb12;
+-     }
+- 
+-     bb5: {
+-         _0 = const u8::MAX;
+-         goto -> bb12;
+-     }
+- 
+-     bb6: {
+-         _0 = const 128_u8;
+-         goto -> bb12;
+-     }
+- 
+-     bb7: {
+-         _0 = const 127_u8;
+-         goto -> bb12;
+-     }
+- 
+-     bb8: {
+-         _0 = const 1_u8;
+-         goto -> bb12;
+-     }
+- 
+-     bb9: {
+-         _0 = const 0_u8;
+-         goto -> bb12;
+-     }
+- 
+-     bb10: {
+-         _0 = const u8::MAX;
+-         goto -> bb12;
+-     }
+- 
+-     bb11: {
+-         _0 = const 128_u8;
+-         goto -> bb12;
+-     }
+- 
+-     bb12: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u8 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..1c0ffb30c5b
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff
@@ -0,0 +1,72 @@
+- // MIR for `match_trunc_i16_u8_failed` before MatchBranchSimplification
++ // MIR for `match_trunc_i16_u8_failed` after MatchBranchSimplification
+  
+  fn match_trunc_i16_u8_failed(_1: EnumAi16) -> u8 {
+      debug i => _1;
+      let mut _0: u8;
+      let mut _2: i16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [128: bb11, 255: bb10, 0: bb9, 1: bb8, 127: bb7, 65408: bb6, 65535: bb5, 65280: bb4, 65281: bb3, 65407: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const -127_i8 as u8 (IntToInt);
+          goto -> bb12;
+      }
+  
+      bb3: {
+          _0 = const 1_u8;
+          goto -> bb12;
+      }
+  
+      bb4: {
+          _0 = const 0_u8;
+          goto -> bb12;
+      }
+  
+      bb5: {
+          _0 = const u8::MAX;
+          goto -> bb12;
+      }
+  
+      bb6: {
+          _0 = const 128_u8;
+          goto -> bb12;
+      }
+  
+      bb7: {
+          _0 = const 127_u8;
+          goto -> bb12;
+      }
+  
+      bb8: {
+          _0 = const 1_u8;
+          goto -> bb12;
+      }
+  
+      bb9: {
+          _0 = const 0_u8;
+          goto -> bb12;
+      }
+  
+      bb10: {
+          _0 = const u8::MAX;
+          goto -> bb12;
+      }
+  
+      bb11: {
+          _0 = const 128_u8;
+          goto -> bb12;
+      }
+  
+      bb12: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..85f97a13cac
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff
@@ -0,0 +1,67 @@
+- // MIR for `match_trunc_u16_i8` before MatchBranchSimplification
++ // MIR for `match_trunc_u16_i8` after MatchBranchSimplification
+  
+  fn match_trunc_u16_i8(_1: EnumAu16) -> i8 {
+      debug i => _1;
+      let mut _0: i8;
+      let mut _2: u16;
++     let mut _3: u16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [0: bb9, 127: bb8, 128: bb7, 255: bb6, 65280: bb5, 65407: bb4, 65408: bb3, 65535: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const -1_i8;
+-         goto -> bb10;
+-     }
+- 
+-     bb3: {
+-         _0 = const i8::MIN;
+-         goto -> bb10;
+-     }
+- 
+-     bb4: {
+-         _0 = const i8::MAX;
+-         goto -> bb10;
+-     }
+- 
+-     bb5: {
+-         _0 = const 0_i8;
+-         goto -> bb10;
+-     }
+- 
+-     bb6: {
+-         _0 = const -1_i8;
+-         goto -> bb10;
+-     }
+- 
+-     bb7: {
+-         _0 = const i8::MIN;
+-         goto -> bb10;
+-     }
+- 
+-     bb8: {
+-         _0 = const i8::MAX;
+-         goto -> bb10;
+-     }
+- 
+-     bb9: {
+-         _0 = const 0_i8;
+-         goto -> bb10;
+-     }
+- 
+-     bb10: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i8 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..cf6c86a71ad
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff
@@ -0,0 +1,62 @@
+- // MIR for `match_trunc_u16_i8_failed` before MatchBranchSimplification
++ // MIR for `match_trunc_u16_i8_failed` after MatchBranchSimplification
+  
+  fn match_trunc_u16_i8_failed(_1: EnumAu16) -> i8 {
+      debug i => _1;
+      let mut _0: i8;
+      let mut _2: u16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [0: bb9, 127: bb8, 128: bb7, 255: bb6, 65280: bb5, 65407: bb4, 65408: bb3, 65535: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 1_i8;
+          goto -> bb10;
+      }
+  
+      bb3: {
+          _0 = const i8::MIN;
+          goto -> bb10;
+      }
+  
+      bb4: {
+          _0 = const i8::MAX;
+          goto -> bb10;
+      }
+  
+      bb5: {
+          _0 = const 0_i8;
+          goto -> bb10;
+      }
+  
+      bb6: {
+          _0 = const -1_i8;
+          goto -> bb10;
+      }
+  
+      bb7: {
+          _0 = const i8::MIN;
+          goto -> bb10;
+      }
+  
+      bb8: {
+          _0 = const i8::MAX;
+          goto -> bb10;
+      }
+  
+      bb9: {
+          _0 = const 0_i8;
+          goto -> bb10;
+      }
+  
+      bb10: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..768d838eaa6
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff
@@ -0,0 +1,67 @@
+- // MIR for `match_trunc_u16_u8` before MatchBranchSimplification
++ // MIR for `match_trunc_u16_u8` after MatchBranchSimplification
+  
+  fn match_trunc_u16_u8(_1: EnumAu16) -> u8 {
+      debug i => _1;
+      let mut _0: u8;
+      let mut _2: u16;
++     let mut _3: u16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [0: bb9, 127: bb8, 128: bb7, 255: bb6, 65280: bb5, 65407: bb4, 65408: bb3, 65535: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const u8::MAX;
+-         goto -> bb10;
+-     }
+- 
+-     bb3: {
+-         _0 = const 128_u8;
+-         goto -> bb10;
+-     }
+- 
+-     bb4: {
+-         _0 = const 127_u8;
+-         goto -> bb10;
+-     }
+- 
+-     bb5: {
+-         _0 = const 0_u8;
+-         goto -> bb10;
+-     }
+- 
+-     bb6: {
+-         _0 = const u8::MAX;
+-         goto -> bb10;
+-     }
+- 
+-     bb7: {
+-         _0 = const 128_u8;
+-         goto -> bb10;
+-     }
+- 
+-     bb8: {
+-         _0 = const 127_u8;
+-         goto -> bb10;
+-     }
+- 
+-     bb9: {
+-         _0 = const 0_u8;
+-         goto -> bb10;
+-     }
+- 
+-     bb10: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u8 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..109e97bb578
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff
@@ -0,0 +1,62 @@
+- // MIR for `match_trunc_u16_u8_failed` before MatchBranchSimplification
++ // MIR for `match_trunc_u16_u8_failed` after MatchBranchSimplification
+  
+  fn match_trunc_u16_u8_failed(_1: EnumAu16) -> u8 {
+      debug i => _1;
+      let mut _0: u8;
+      let mut _2: u16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [0: bb9, 127: bb8, 128: bb7, 255: bb6, 65280: bb5, 65407: bb4, 65408: bb3, 65535: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 127_u8;
+          goto -> bb10;
+      }
+  
+      bb3: {
+          _0 = const 128_u8;
+          goto -> bb10;
+      }
+  
+      bb4: {
+          _0 = const 127_u8;
+          goto -> bb10;
+      }
+  
+      bb5: {
+          _0 = const 0_u8;
+          goto -> bb10;
+      }
+  
+      bb6: {
+          _0 = const u8::MAX;
+          goto -> bb10;
+      }
+  
+      bb7: {
+          _0 = const 128_u8;
+          goto -> bb10;
+      }
+  
+      bb8: {
+          _0 = const 127_u8;
+          goto -> bb10;
+      }
+  
+      bb9: {
+          _0 = const 0_u8;
+          goto -> bb10;
+      }
+  
+      bb10: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff
deleted file mode 100644
index 72ad60956ab..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,32 +0,0 @@
-- // MIR for `match_u8_i16` before MatchBranchSimplification
-+ // MIR for `match_u8_i16` after MatchBranchSimplification
-  
-  fn match_u8_i16(_1: EnumAu8) -> i16 {
-      debug i => _1;
-      let mut _0: i16;
-      let mut _2: u8;
-  
-      bb0: {
-          _2 = discriminant(_1);
-          switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const 2_i16;
-          goto -> bb4;
-      }
-  
-      bb3: {
-          _0 = const 1_i16;
-          goto -> bb4;
-      }
-  
-      bb4: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff
deleted file mode 100644
index 3333cd765a8..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,26 +0,0 @@
-- // MIR for `match_u8_i16_2` before MatchBranchSimplification
-+ // MIR for `match_u8_i16_2` after MatchBranchSimplification
-  
-  fn match_u8_i16_2(_1: EnumAu8) -> i16 {
-      let mut _0: i16;
-      let mut _2: u8;
-  
-      bb0: {
-          _2 = discriminant(_1);
-          switchInt(_2) -> [1: bb3, 2: bb1, otherwise: bb2];
-      }
-  
-      bb1: {
-          _0 = const 2_i16;
-          goto -> bb3;
-      }
-  
-      bb2: {
-          unreachable;
-      }
-  
-      bb3: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff
deleted file mode 100644
index 6da19e46dab..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,32 +0,0 @@
-- // MIR for `match_u8_i16_failed` before MatchBranchSimplification
-+ // MIR for `match_u8_i16_failed` after MatchBranchSimplification
-  
-  fn match_u8_i16_failed(_1: EnumAu8) -> i16 {
-      debug i => _1;
-      let mut _0: i16;
-      let mut _2: u8;
-  
-      bb0: {
-          _2 = discriminant(_1);
-          switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const 3_i16;
-          goto -> bb4;
-      }
-  
-      bb3: {
-          _0 = const 1_i16;
-          goto -> bb4;
-      }
-  
-      bb4: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff
deleted file mode 100644
index 5690f17f24f..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,31 +0,0 @@
-- // MIR for `match_u8_i16_fallback` before MatchBranchSimplification
-+ // MIR for `match_u8_i16_fallback` after MatchBranchSimplification
-  
-  fn match_u8_i16_fallback(_1: u8) -> i16 {
-      debug i => _1;
-      let mut _0: i16;
-  
-      bb0: {
-          switchInt(_1) -> [1: bb3, 2: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          _0 = const 3_i16;
-          goto -> bb4;
-      }
-  
-      bb2: {
-          _0 = const 2_i16;
-          goto -> bb4;
-      }
-  
-      bb3: {
-          _0 = const 1_i16;
-          goto -> bb4;
-      }
-  
-      bb4: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..d63eed7c019
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff
@@ -0,0 +1,47 @@
+- // MIR for `match_u8_i8` before MatchBranchSimplification
++ // MIR for `match_u8_i8` after MatchBranchSimplification
+  
+  fn match_u8_i8(_1: EnumAu8) -> i8 {
+      debug i => _1;
+      let mut _0: i8;
+      let mut _2: u8;
++     let mut _3: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const -1_i8;
+-         goto -> bb6;
+-     }
+- 
+-     bb3: {
+-         _0 = const i8::MIN;
+-         goto -> bb6;
+-     }
+- 
+-     bb4: {
+-         _0 = const i8::MAX;
+-         goto -> bb6;
+-     }
+- 
+-     bb5: {
+-         _0 = const 0_i8;
+-         goto -> bb6;
+-     }
+- 
+-     bb6: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i8 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..98dee1835a8
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff
@@ -0,0 +1,80 @@
+- // MIR for `match_u8_i8_2` before MatchBranchSimplification
++ // MIR for `match_u8_i8_2` after MatchBranchSimplification
+  
+  fn match_u8_i8_2(_1: EnumAu8) -> (i8, i8) {
+      debug i => _1;
+      let mut _0: (i8, i8);
+      let _2: i8;
+      let _4: ();
+      let mut _5: u8;
+      let mut _6: i8;
+      let mut _7: i8;
++     let mut _8: u8;
+      scope 1 {
+          debug a => _2;
+          let _3: i8;
+          scope 2 {
+              debug b => _3;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _5 = discriminant(_1);
+-         switchInt(move _5) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _2 = const -1_i8;
+-         _3 = const -1_i8;
++         StorageLive(_8);
++         _8 = move _5;
++         _2 = _8 as i8 (IntToInt);
++         _3 = _8 as i8 (IntToInt);
+          _4 = ();
+-         goto -> bb6;
+-     }
+- 
+-     bb3: {
+-         _2 = const i8::MIN;
+-         _3 = const i8::MIN;
+-         _4 = ();
+-         goto -> bb6;
+-     }
+- 
+-     bb4: {
+-         _2 = const i8::MAX;
+-         _3 = const i8::MAX;
+-         _4 = ();
+-         goto -> bb6;
+-     }
+- 
+-     bb5: {
+-         _2 = const 0_i8;
+-         _3 = const 0_i8;
+-         _4 = ();
+-         goto -> bb6;
+-     }
+- 
+-     bb6: {
++         StorageDead(_8);
+          StorageDead(_4);
+          StorageLive(_6);
+          _6 = _2;
+          StorageLive(_7);
+          _7 = _3;
+          _0 = (move _6, move _7);
+          StorageDead(_7);
+          StorageDead(_6);
+          StorageDead(_3);
+          StorageDead(_2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..901dda58617
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff
@@ -0,0 +1,74 @@
+- // MIR for `match_u8_i8_2_failed` before MatchBranchSimplification
++ // MIR for `match_u8_i8_2_failed` after MatchBranchSimplification
+  
+  fn match_u8_i8_2_failed(_1: EnumAu8) -> (i8, i8) {
+      debug i => _1;
+      let mut _0: (i8, i8);
+      let _2: i8;
+      let _4: ();
+      let mut _5: u8;
+      let mut _6: i8;
+      let mut _7: i8;
+      scope 1 {
+          debug a => _2;
+          let _3: i8;
+          scope 2 {
+              debug b => _3;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _5 = discriminant(_1);
+          switchInt(move _5) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _2 = const -1_i8;
+          _3 = const 1_i8;
+          _4 = ();
+          goto -> bb6;
+      }
+  
+      bb3: {
+          _2 = const i8::MIN;
+          _3 = const i8::MIN;
+          _4 = ();
+          goto -> bb6;
+      }
+  
+      bb4: {
+          _2 = const i8::MAX;
+          _3 = const i8::MAX;
+          _4 = ();
+          goto -> bb6;
+      }
+  
+      bb5: {
+          _2 = const 0_i8;
+          _3 = const 0_i8;
+          _4 = ();
+          goto -> bb6;
+      }
+  
+      bb6: {
+          StorageDead(_4);
+          StorageLive(_6);
+          _6 = _2;
+          StorageLive(_7);
+          _7 = _3;
+          _0 = (move _6, move _7);
+          StorageDead(_7);
+          StorageDead(_6);
+          StorageDead(_3);
+          StorageDead(_2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..ac96be55312
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff
@@ -0,0 +1,42 @@
+- // MIR for `match_u8_i8_failed` before MatchBranchSimplification
++ // MIR for `match_u8_i8_failed` after MatchBranchSimplification
+  
+  fn match_u8_i8_failed(_1: EnumAu8) -> i8 {
+      debug i => _1;
+      let mut _0: i8;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 1_i8;
+          goto -> bb6;
+      }
+  
+      bb3: {
+          _0 = const i8::MIN;
+          goto -> bb6;
+      }
+  
+      bb4: {
+          _0 = const i8::MAX;
+          goto -> bb6;
+      }
+  
+      bb5: {
+          _0 = const 0_i8;
+          goto -> bb6;
+      }
+  
+      bb6: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..9ebf2cf27cb
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff
@@ -0,0 +1,42 @@
+- // MIR for `match_u8_i8_failed_len_1` before MatchBranchSimplification
++ // MIR for `match_u8_i8_failed_len_1` after MatchBranchSimplification
+  
+  fn match_u8_i8_failed_len_1(_1: EnumAu8) -> i8 {
+      let mut _0: i8;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(_2) -> [0: bb1, 127: bb2, 128: bb3, 255: bb4, otherwise: bb5];
+      }
+  
+      bb1: {
+          _0 = const 0_i8;
+          goto -> bb6;
+      }
+  
+      bb2: {
+          _0 = const i8::MAX;
+          _0 = const i8::MAX;
+          goto -> bb6;
+      }
+  
+      bb3: {
+          _0 = const i8::MIN;
+          goto -> bb6;
+      }
+  
+      bb4: {
+          _0 = const -1_i8;
+          goto -> bb6;
+      }
+  
+      bb5: {
+          unreachable;
+      }
+  
+      bb6: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..554856777eb
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff
@@ -0,0 +1,42 @@
+- // MIR for `match_u8_i8_failed_len_2` before MatchBranchSimplification
++ // MIR for `match_u8_i8_failed_len_2` after MatchBranchSimplification
+  
+  fn match_u8_i8_failed_len_2(_1: EnumAu8) -> i8 {
+      let mut _0: i8;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(_2) -> [0: bb1, 127: bb2, 128: bb3, 255: bb4, otherwise: bb5];
+      }
+  
+      bb1: {
+          _0 = const 0_i8;
+          goto -> bb6;
+      }
+  
+      bb2: {
+          _0 = const i8::MAX;
+          goto -> bb6;
+      }
+  
+      bb3: {
+          _0 = const i8::MIN;
+          goto -> bb6;
+      }
+  
+      bb4: {
+          _0 = const -1_i8;
+          _0 = const -1_i8;
+          goto -> bb6;
+      }
+  
+      bb5: {
+          unreachable;
+      }
+  
+      bb6: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..356655021f7
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff
@@ -0,0 +1,38 @@
+- // MIR for `match_u8_i8_fallback` before MatchBranchSimplification
++ // MIR for `match_u8_i8_fallback` after MatchBranchSimplification
+  
+  fn match_u8_i8_fallback(_1: EnumAu8) -> i8 {
+      debug i => _1;
+      let mut _0: i8;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [0: bb4, 127: bb3, 128: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          _0 = const -1_i8;
+          goto -> bb5;
+      }
+  
+      bb2: {
+          _0 = const i8::MIN;
+          goto -> bb5;
+      }
+  
+      bb3: {
+          _0 = const i8::MAX;
+          goto -> bb5;
+      }
+  
+      bb4: {
+          _0 = const 0_i8;
+          goto -> bb5;
+      }
+  
+      bb5: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff
deleted file mode 100644
index dc9c1c2b97f..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,37 +0,0 @@
-- // MIR for `match_u8_u16` before MatchBranchSimplification
-+ // MIR for `match_u8_u16` after MatchBranchSimplification
-  
-  fn match_u8_u16(_1: EnumBu8) -> u16 {
-      debug i => _1;
-      let mut _0: u16;
-      let mut _2: u8;
-  
-      bb0: {
-          _2 = discriminant(_1);
-          switchInt(move _2) -> [1: bb4, 2: bb3, 5: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const 5_u16;
-          goto -> bb5;
-      }
-  
-      bb3: {
-          _0 = const 2_u16;
-          goto -> bb5;
-      }
-  
-      bb4: {
-          _0 = const 1_u16;
-          goto -> bb5;
-      }
-  
-      bb5: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff
deleted file mode 100644
index b47de6a52b7..00000000000
--- a/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff
+++ /dev/null
@@ -1,37 +0,0 @@
-- // MIR for `match_u8_u16_2` before MatchBranchSimplification
-+ // MIR for `match_u8_u16_2` after MatchBranchSimplification
-  
-  fn match_u8_u16_2(_1: EnumBu8) -> i16 {
-      let mut _0: i16;
-      let mut _2: u8;
-  
-      bb0: {
-          _2 = discriminant(_1);
-          switchInt(_2) -> [1: bb1, 2: bb2, 5: bb3, otherwise: bb4];
-      }
-  
-      bb1: {
-          _0 = const 1_i16;
-          goto -> bb5;
-      }
-  
-      bb2: {
-          _0 = const 2_i16;
-          goto -> bb5;
-      }
-  
-      bb3: {
-          _0 = const 5_i16;
-          _0 = const 5_i16;
-          goto -> bb5;
-      }
-  
-      bb4: {
-          unreachable;
-      }
-  
-      bb5: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..e00a604fe25
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff
@@ -0,0 +1,47 @@
+- // MIR for `match_zext_u8_i16` before MatchBranchSimplification
++ // MIR for `match_zext_u8_i16` after MatchBranchSimplification
+  
+  fn match_zext_u8_i16(_1: EnumAu8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+      let mut _2: u8;
++     let mut _3: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 255_i16;
+-         goto -> bb6;
+-     }
+- 
+-     bb3: {
+-         _0 = const 128_i16;
+-         goto -> bb6;
+-     }
+- 
+-     bb4: {
+-         _0 = const 127_i16;
+-         goto -> bb6;
+-     }
+- 
+-     bb5: {
+-         _0 = const 0_i16;
+-         goto -> bb6;
+-     }
+- 
+-     bb6: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i16 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..a19cd796c27
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff
@@ -0,0 +1,42 @@
+- // MIR for `match_zext_u8_i16_failed` before MatchBranchSimplification
++ // MIR for `match_zext_u8_i16_failed` after MatchBranchSimplification
+  
+  fn match_zext_u8_i16_failed(_1: EnumAu8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 255_i16;
+          goto -> bb6;
+      }
+  
+      bb3: {
+          _0 = const 128_i16;
+          goto -> bb6;
+      }
+  
+      bb4: {
+          _0 = const -127_i16;
+          goto -> bb6;
+      }
+  
+      bb5: {
+          _0 = const 0_i16;
+          goto -> bb6;
+      }
+  
+      bb6: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..befb9118907
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff
@@ -0,0 +1,47 @@
+- // MIR for `match_zext_u8_u16` before MatchBranchSimplification
++ // MIR for `match_zext_u8_u16` after MatchBranchSimplification
+  
+  fn match_zext_u8_u16(_1: EnumAu8) -> u16 {
+      debug i => _1;
+      let mut _0: u16;
+      let mut _2: u8;
++     let mut _3: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 255_u16;
+-         goto -> bb6;
+-     }
+- 
+-     bb3: {
+-         _0 = const 128_u16;
+-         goto -> bb6;
+-     }
+- 
+-     bb4: {
+-         _0 = const 127_u16;
+-         goto -> bb6;
+-     }
+- 
+-     bb5: {
+-         _0 = const 0_u16;
+-         goto -> bb6;
+-     }
+- 
+-     bb6: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u16 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..f781f88449d
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff
@@ -0,0 +1,42 @@
+- // MIR for `match_zext_u8_u16_failed` before MatchBranchSimplification
++ // MIR for `match_zext_u8_u16_failed` after MatchBranchSimplification
+  
+  fn match_zext_u8_u16_failed(_1: EnumAu8) -> u16 {
+      debug i => _1;
+      let mut _0: u16;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [0: bb5, 127: bb4, 128: bb3, 255: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 255_u16;
+          goto -> bb6;
+      }
+  
+      bb3: {
+          _0 = const 128_u16;
+          goto -> bb6;
+      }
+  
+      bb4: {
+          _0 = const 65407_u16;
+          goto -> bb6;
+      }
+  
+      bb5: {
+          _0 = const 0_u16;
+          goto -> bb6;
+      }
+  
+      bb6: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs
index 176d68bcd40..6787e5816a3 100644
--- a/tests/mir-opt/matches_reduce_branches.rs
+++ b/tests/mir-opt/matches_reduce_branches.rs
@@ -3,6 +3,7 @@
 #![feature(repr128)]
 #![feature(core_intrinsics)]
 #![feature(custom_mir)]
+#![allow(non_camel_case_types)]
 
 use std::intrinsics::mir::*;
 
@@ -12,6 +13,7 @@ fn foo(bar: Option<()>) {
     // CHECK: = Eq(
     // CHECK: switchInt
     // CHECK-NOT: switchInt
+    // CHECK: return
     if matches!(bar, None) {
         ()
     }
@@ -23,6 +25,7 @@ fn bar(i: i32) -> (bool, bool, bool, bool) {
     // CHECK: = Ne(
     // CHECK: = Eq(
     // CHECK-NOT: switchInt
+    // CHECK: return
     let a;
     let b;
     let c;
@@ -52,6 +55,7 @@ fn bar(i: i32) -> (bool, bool, bool, bool) {
 fn match_nested_if() -> bool {
     // CHECK-LABEL: fn match_nested_if(
     // CHECK-NOT: switchInt
+    // CHECK: return
     let val = match () {
         () if if if if true { true } else { false } { true } else { false } {
             true
@@ -66,42 +70,170 @@ fn match_nested_if() -> bool {
     val
 }
 
+// # Fold switchInt into IntToInt.
+// To simplify writing and checking these test cases, I use the first character of
+// each case to distinguish the sign of the number:
+// 'u' for unsigned, '_' for negative, and 'o' for non-negative.
+// Followed by a decimal number, and add the corresponding radix representation.
+// For example, o127_0x7f represents 127i8, and _1_0xff represents -1i8.
+
+// ## Cast but without numeric conversion.
+
 #[repr(u8)]
 enum EnumAu8 {
-    A = 1,
-    B = 2,
+    u0_0x00 = 0,
+    u127_0x7f = 127,
+    u128_0x80 = 128,
+    u255_0xff = 255,
+}
+
+#[repr(i8)]
+enum EnumAi8 {
+    _128_0x80 = -128,
+    _1_0xff = -1,
+    o0_0x00 = 0,
+    o1_0x01 = 1,
+    o127_0x7f = 127,
 }
 
-// EMIT_MIR matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff
-fn match_u8_i16(i: EnumAu8) -> i16 {
-    // CHECK-LABEL: fn match_u8_i16(
+// EMIT_MIR matches_reduce_branches.match_u8_i8.MatchBranchSimplification.diff
+fn match_u8_i8(i: EnumAu8) -> i8 {
+    // CHECK-LABEL: fn match_u8_i8(
+    // CHECK-NOT: switchInt
+    // CHECK: return
+    match i {
+        EnumAu8::u0_0x00 => 0,
+        EnumAu8::u127_0x7f => 127,
+        EnumAu8::u128_0x80 => -128,
+        EnumAu8::u255_0xff => -1,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_i8_failed.MatchBranchSimplification.diff
+fn match_u8_i8_failed(i: EnumAu8) -> i8 {
+    // CHECK-LABEL: fn match_u8_i8_failed(
     // CHECK: switchInt
+    // CHECK: return
     match i {
-        EnumAu8::A => 1,
-        EnumAu8::B => 2,
+        EnumAu8::u0_0x00 => 0,
+        EnumAu8::u127_0x7f => 127,
+        EnumAu8::u128_0x80 => -128,
+        EnumAu8::u255_0xff => 1, // failed
     }
 }
 
-// EMIT_MIR matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff
+// EMIT_MIR matches_reduce_branches.match_u8_i8_2.MatchBranchSimplification.diff
+fn match_u8_i8_2(i: EnumAu8) -> (i8, i8) {
+    // CHECK-LABEL: fn match_u8_i8_2(
+    // CHECK-NOT: switchInt
+    // CHECK: IntToInt
+    // CHECK: IntToInt
+    // CHECK: return
+    let a: i8;
+    let b: i8;
+    match i {
+        EnumAu8::u0_0x00 => {
+            a = 0;
+            b = 0;
+            ()
+        }
+        EnumAu8::u127_0x7f => {
+            a = 127;
+            b = 127;
+            ()
+        }
+        EnumAu8::u128_0x80 => {
+            a = -128;
+            b = -128;
+            ()
+        }
+        EnumAu8::u255_0xff => {
+            a = -1;
+            b = -1;
+            ()
+        }
+    };
+    (a, b)
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_i8_2_failed.MatchBranchSimplification.diff
+fn match_u8_i8_2_failed(i: EnumAu8) -> (i8, i8) {
+    // CHECK-LABEL: fn match_u8_i8_2_failed(
+    // CHECK: switchInt
+    // CHECK: return
+    let a: i8;
+    let b: i8;
+    match i {
+        EnumAu8::u0_0x00 => {
+            a = 0;
+            b = 0;
+            ()
+        }
+        EnumAu8::u127_0x7f => {
+            a = 127;
+            b = 127;
+            ()
+        }
+        EnumAu8::u128_0x80 => {
+            a = -128;
+            b = -128;
+            ()
+        }
+        EnumAu8::u255_0xff => {
+            a = -1;
+            b = 1; // failed
+            ()
+        }
+    };
+    (a, b)
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_i8_fallback.MatchBranchSimplification.diff
+fn match_u8_i8_fallback(i: EnumAu8) -> i8 {
+    // CHECK-LABEL: fn match_u8_i8_fallback(
+    // CHECK: switchInt
+    // CHECK: return
+    match i {
+        EnumAu8::u0_0x00 => 0,
+        EnumAu8::u127_0x7f => 127,
+        EnumAu8::u128_0x80 => -128,
+        _ => -1,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_i8_failed_len_1.MatchBranchSimplification.diff
 // Check for different instruction lengths
 #[custom_mir(dialect = "built")]
-fn match_u8_i16_2(i: EnumAu8) -> i16 {
-    // CHECK-LABEL: fn match_u8_i16_2(
+fn match_u8_i8_failed_len_1(i: EnumAu8) -> i8 {
+    // CHECK-LABEL: fn match_u8_i8_failed_len_1(
     // CHECK: switchInt
+    // CHECK: return
     mir! {
         {
             let a = Discriminant(i);
             match a {
-                1 => bb1,
-                2 => bb2,
+                0 => bb1,
+                127 => bb2,
+                128 => bb3,
+                255 => bb4,
                 _ => unreachable_bb,
             }
         }
         bb1 = {
+            RET = 0;
             Goto(ret)
         }
         bb2 = {
-            RET = 2;
+            RET = 127;
+            RET = 127;
+            Goto(ret)
+        }
+        bb3 = {
+            RET = -128;
+            Goto(ret)
+        }
+        bb4 = {
+            RET = -1;
             Goto(ret)
         }
         unreachable_bb = {
@@ -113,72 +245,39 @@ fn match_u8_i16_2(i: EnumAu8) -> i16 {
     }
 }
 
-// EMIT_MIR matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff
-fn match_u8_i16_failed(i: EnumAu8) -> i16 {
-    // CHECK-LABEL: fn match_u8_i16_failed(
-    // CHECK: switchInt
-    match i {
-        EnumAu8::A => 1,
-        EnumAu8::B => 3,
-    }
-}
-
-// EMIT_MIR matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff
-fn match_u8_i16_fallback(i: u8) -> i16 {
-    // CHECK-LABEL: fn match_u8_i16_fallback(
-    // CHECK: switchInt
-    match i {
-        1 => 1,
-        2 => 2,
-        _ => 3,
-    }
-}
-
-#[repr(u8)]
-enum EnumBu8 {
-    A = 1,
-    B = 2,
-    C = 5,
-}
-
-// EMIT_MIR matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff
-fn match_u8_u16(i: EnumBu8) -> u16 {
-    // CHECK-LABEL: fn match_u8_u16(
-    // CHECK: switchInt
-    match i {
-        EnumBu8::A => 1,
-        EnumBu8::B => 2,
-        EnumBu8::C => 5,
-    }
-}
-
-// EMIT_MIR matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff
+// EMIT_MIR matches_reduce_branches.match_u8_i8_failed_len_2.MatchBranchSimplification.diff
 // Check for different instruction lengths
 #[custom_mir(dialect = "built")]
-fn match_u8_u16_2(i: EnumBu8) -> i16 {
-    // CHECK-LABEL: fn match_u8_u16_2(
+fn match_u8_i8_failed_len_2(i: EnumAu8) -> i8 {
+    // CHECK-LABEL: fn match_u8_i8_failed_len_2(
     // CHECK: switchInt
+    // CHECK: return
     mir! {
         {
             let a = Discriminant(i);
             match a {
-                1 => bb1,
-                2 => bb2,
-                5 => bb5,
+                0 => bb1,
+                127 => bb2,
+                128 => bb3,
+                255 => bb4,
                 _ => unreachable_bb,
             }
         }
         bb1 = {
-            RET = 1;
+            RET = 0;
             Goto(ret)
         }
         bb2 = {
-            RET = 2;
+            RET = 127;
             Goto(ret)
         }
-        bb5 = {
-            RET = 5;
-            RET = 5;
+        bb3 = {
+            RET = -128;
+            Goto(ret)
+        }
+        bb4 = {
+            RET = -1;
+            RET = -1;
             Goto(ret)
         }
         unreachable_bb = {
@@ -190,50 +289,309 @@ fn match_u8_u16_2(i: EnumBu8) -> i16 {
     }
 }
 
-#[repr(i8)]
-enum EnumAi8 {
-    A = -1,
-    B = 2,
-    C = -3,
+// ## Cast with sext.
+
+// EMIT_MIR matches_reduce_branches.match_sext_i8_i16.MatchBranchSimplification.diff
+fn match_sext_i8_i16(i: EnumAi8) -> i16 {
+    // CHECK-LABEL: fn match_sext_i8_i16(
+    // CHECK-NOT: switchInt
+    // CHECK: return
+    match i {
+        EnumAi8::_128_0x80 => -128,
+        EnumAi8::_1_0xff => -1,
+        EnumAi8::o0_0x00 => 0,
+        EnumAi8::o1_0x01 => 1,
+        EnumAi8::o127_0x7f => 127,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_sext_i8_i16_failed.MatchBranchSimplification.diff
+// Converting `-1i8` to `255i16` is zext.
+fn match_sext_i8_i16_failed(i: EnumAi8) -> i16 {
+    // CHECK-LABEL: fn match_sext_i8_i16_failed(
+    // CHECK: switchInt
+    // CHECK: return
+    match i {
+        EnumAi8::_128_0x80 => -128,
+        EnumAi8::_1_0xff => 255, // failed
+        EnumAi8::o0_0x00 => 0,
+        EnumAi8::o1_0x01 => 1,
+        EnumAi8::o127_0x7f => 127,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_sext_i8_u16.MatchBranchSimplification.diff
+fn match_sext_i8_u16(i: EnumAi8) -> u16 {
+    // CHECK-LABEL: fn match_sext_i8_u16(
+    // CHECK-NOT: switchInt
+    // CHECK: return
+    match i {
+        EnumAi8::_128_0x80 => 0xff80,
+        EnumAi8::_1_0xff => 0xffff,
+        EnumAi8::o0_0x00 => 0,
+        EnumAi8::o1_0x01 => 1,
+        EnumAi8::o127_0x7f => 127,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_sext_i8_u16_failed.MatchBranchSimplification.diff
+// Converting `-1i8` to `255u16` is zext.
+fn match_sext_i8_u16_failed(i: EnumAi8) -> u16 {
+    // CHECK-LABEL: fn match_sext_i8_u16_failed(
+    // CHECK: switchInt
+    // CHECK: return
+    match i {
+        EnumAi8::_128_0x80 => 0xff80,
+        EnumAi8::_1_0xff => 0x00ff, // failed
+        EnumAi8::o0_0x00 => 0,
+        EnumAi8::o1_0x01 => 1,
+        EnumAi8::o127_0x7f => 127,
+    }
+}
+
+// ## Cast with zext.
+
+// EMIT_MIR matches_reduce_branches.match_zext_u8_u16.MatchBranchSimplification.diff
+fn match_zext_u8_u16(i: EnumAu8) -> u16 {
+    // CHECK-LABEL: fn match_zext_u8_u16(
+    // CHECK-NOT: switchInt
+    // CHECK: return
+    match i {
+        EnumAu8::u0_0x00 => 0,
+        EnumAu8::u127_0x7f => 0x7f,
+        EnumAu8::u128_0x80 => 128,
+        EnumAu8::u255_0xff => 255,
+    }
 }
 
-// EMIT_MIR matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff
-fn match_i8_i16(i: EnumAi8) -> i16 {
-    // CHECK-LABEL: fn match_i8_i16(
+// EMIT_MIR matches_reduce_branches.match_zext_u8_u16_failed.MatchBranchSimplification.diff
+fn match_zext_u8_u16_failed(i: EnumAu8) -> u16 {
+    // CHECK-LABEL: fn match_zext_u8_u16_failed(
     // CHECK: switchInt
+    // CHECK: return
+    match i {
+        EnumAu8::u0_0x00 => 0,
+        EnumAu8::u127_0x7f => 0xff7f, // failed
+        EnumAu8::u128_0x80 => 128,
+        EnumAu8::u255_0xff => 255,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_zext_u8_i16.MatchBranchSimplification.diff
+fn match_zext_u8_i16(i: EnumAu8) -> i16 {
+    // CHECK-LABEL: fn match_zext_u8_i16(
+    // CHECK-NOT: switchInt
+    // CHECK: return
     match i {
-        EnumAi8::A => -1,
-        EnumAi8::B => 2,
-        EnumAi8::C => -3,
+        EnumAu8::u0_0x00 => 0,
+        EnumAu8::u127_0x7f => 127,
+        EnumAu8::u128_0x80 => 128,
+        EnumAu8::u255_0xff => 255,
     }
 }
 
-// EMIT_MIR matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff
-fn match_i8_i16_failed(i: EnumAi8) -> i16 {
-    // CHECK-LABEL: fn match_i8_i16_failed(
+// EMIT_MIR matches_reduce_branches.match_zext_u8_i16_failed.MatchBranchSimplification.diff
+fn match_zext_u8_i16_failed(i: EnumAu8) -> i16 {
+    // CHECK-LABEL: fn match_zext_u8_i16_failed(
     // CHECK: switchInt
+    // CHECK: return
     match i {
-        EnumAi8::A => -1,
-        EnumAi8::B => 2,
-        EnumAi8::C => 3,
+        EnumAu8::u0_0x00 => 0,
+        EnumAu8::u127_0x7f => -127, // failed
+        EnumAu8::u128_0x80 => 128,
+        EnumAu8::u255_0xff => 255,
     }
 }
 
+// ## Cast with trunc.
+
+#[repr(u16)]
+enum EnumAu16 {
+    // 0x00nn
+    u0_0x0000 = 0,
+    u127_0x007f = 127,
+    u128_0x0080 = 128,
+    u255_0x00ff = 255,
+    // 0xffnn
+    u65280_0xff00 = 65280,
+    u65407_0xff7f = 65407,
+    u65408_0xff80 = 65408,
+    u65535_0xffff = 65535,
+}
+
 #[repr(i16)]
 enum EnumAi16 {
-    A = -1,
-    B = 2,
-    C = -3,
+    // 0x00nn
+    o128_0x0080 = 128,
+    o255_0x00ff = 255,
+    o0_0x0000 = 0,
+    o1_0x0001 = 1,
+    o127_0x007f = 127,
+    // 0xffnn
+    _128_0xff80 = -128,
+    _1_0xffff = -1,
+    o0_0xff00 = -256,
+    o1_0xff01 = -255,
+    o127_0xff7f = -129,
 }
 
-// EMIT_MIR matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff
-fn match_i16_i8(i: EnumAi16) -> i8 {
-    // CHECK-LABEL: fn match_i16_i8(
+// EMIT_MIR matches_reduce_branches.match_trunc_i16_i8.MatchBranchSimplification.diff
+fn match_trunc_i16_i8(i: EnumAi16) -> i8 {
+    // CHECK-LABEL: fn match_trunc_i16_i8(
+    // CHECK-NOT: switchInt
+    // CHECK: return
+    match i {
+        // 0x00nn
+        EnumAi16::o128_0x0080 => -128,
+        EnumAi16::o255_0x00ff => -1,
+        EnumAi16::o0_0x0000 => 0,
+        EnumAi16::o1_0x0001 => 1,
+        EnumAi16::o127_0x007f => 127,
+        // 0xffnn
+        EnumAi16::_128_0xff80 => -128,
+        EnumAi16::_1_0xffff => -1,
+        EnumAi16::o0_0xff00 => 0,
+        EnumAi16::o1_0xff01 => 1,
+        EnumAi16::o127_0xff7f => 127,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_trunc_i16_i8_failed.MatchBranchSimplification.diff
+fn match_trunc_i16_i8_failed(i: EnumAi16) -> i8 {
+    // CHECK-LABEL: fn match_trunc_i16_i8_failed(
     // CHECK: switchInt
+    // CHECK: return
     match i {
-        EnumAi16::A => -1,
-        EnumAi16::B => 2,
-        EnumAi16::C => -3,
+        // 0x00nn
+        EnumAi16::o128_0x0080 => -128,
+        EnumAi16::o255_0x00ff => -1,
+        EnumAi16::o0_0x0000 => 0,
+        EnumAi16::o1_0x0001 => 1,
+        EnumAi16::o127_0x007f => 127,
+        // 0xffnn
+        EnumAi16::_128_0xff80 => -128,
+        EnumAi16::_1_0xffff => -1,
+        EnumAi16::o0_0xff00 => 0,
+        EnumAi16::o1_0xff01 => 1,
+        EnumAi16::o127_0xff7f => -127, // failed
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_trunc_i16_u8.MatchBranchSimplification.diff
+fn match_trunc_i16_u8(i: EnumAi16) -> u8 {
+    // CHECK-LABEL: fn match_trunc_i16_u8(
+    // CHECK-NOT: switchInt
+    // CHECK: return
+    match i {
+        // 0x00nn
+        EnumAi16::o128_0x0080 => 128,
+        EnumAi16::o255_0x00ff => 255,
+        EnumAi16::o0_0x0000 => 0,
+        EnumAi16::o1_0x0001 => 1,
+        EnumAi16::o127_0x007f => 127,
+        // 0xffnn
+        EnumAi16::_128_0xff80 => 128,
+        EnumAi16::_1_0xffff => 255,
+        EnumAi16::o0_0xff00 => 0,
+        EnumAi16::o1_0xff01 => 1,
+        EnumAi16::o127_0xff7f => 127,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_trunc_i16_u8_failed.MatchBranchSimplification.diff
+fn match_trunc_i16_u8_failed(i: EnumAi16) -> u8 {
+    // CHECK-LABEL: fn match_trunc_i16_u8_failed(
+    // CHECK: switchInt
+    // CHECK: return
+    match i {
+        // 0x00nn
+        EnumAi16::o128_0x0080 => 128,
+        EnumAi16::o255_0x00ff => 255,
+        EnumAi16::o0_0x0000 => 0,
+        EnumAi16::o1_0x0001 => 1,
+        EnumAi16::o127_0x007f => 127,
+        // 0xffnn
+        EnumAi16::_128_0xff80 => 128,
+        EnumAi16::_1_0xffff => 255,
+        EnumAi16::o0_0xff00 => 0,
+        EnumAi16::o1_0xff01 => 1,
+        EnumAi16::o127_0xff7f => -127i8 as u8, // failed
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_trunc_u16_u8.MatchBranchSimplification.diff
+fn match_trunc_u16_u8(i: EnumAu16) -> u8 {
+    // CHECK-LABEL: fn match_trunc_u16_u8(
+    // CHECK-NOT: switchInt
+    // CHECK: return
+    match i {
+        // 0x00nn
+        EnumAu16::u0_0x0000 => 0,
+        EnumAu16::u127_0x007f => 127,
+        EnumAu16::u128_0x0080 => 128,
+        EnumAu16::u255_0x00ff => 255,
+        // 0xffnn
+        EnumAu16::u65280_0xff00 => 0,
+        EnumAu16::u65407_0xff7f => 127,
+        EnumAu16::u65408_0xff80 => 128,
+        EnumAu16::u65535_0xffff => 255,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_trunc_u16_u8_failed.MatchBranchSimplification.diff
+fn match_trunc_u16_u8_failed(i: EnumAu16) -> u8 {
+    // CHECK-LABEL: fn match_trunc_u16_u8_failed(
+    // CHECK: switchInt
+    // CHECK: return
+    match i {
+        // 0x00nn
+        EnumAu16::u0_0x0000 => 0,
+        EnumAu16::u127_0x007f => 127,
+        EnumAu16::u128_0x0080 => 128,
+        EnumAu16::u255_0x00ff => 255,
+        // 0xffnn
+        EnumAu16::u65280_0xff00 => 0,
+        EnumAu16::u65407_0xff7f => 127,
+        EnumAu16::u65408_0xff80 => 128,
+        EnumAu16::u65535_0xffff => 127, // failed
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_trunc_u16_i8.MatchBranchSimplification.diff
+fn match_trunc_u16_i8(i: EnumAu16) -> i8 {
+    // CHECK-LABEL: fn match_trunc_u16_i8(
+    // CHECK-NOT: switchInt
+    // CHECK: return
+    match i {
+        // 0x00nn
+        EnumAu16::u0_0x0000 => 0,
+        EnumAu16::u127_0x007f => 127,
+        EnumAu16::u128_0x0080 => -128,
+        EnumAu16::u255_0x00ff => -1,
+        // 0xffnn
+        EnumAu16::u65280_0xff00 => 0,
+        EnumAu16::u65407_0xff7f => 127,
+        EnumAu16::u65408_0xff80 => -128,
+        EnumAu16::u65535_0xffff => -1,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_trunc_u16_i8_failed.MatchBranchSimplification.diff
+fn match_trunc_u16_i8_failed(i: EnumAu16) -> i8 {
+    // CHECK-LABEL: fn match_trunc_u16_i8_failed(
+    // CHECK: switchInt
+    // CHECK: return
+    match i {
+        // 0x00nn
+        EnumAu16::u0_0x0000 => 0,
+        EnumAu16::u127_0x007f => 127,
+        EnumAu16::u128_0x0080 => -128,
+        EnumAu16::u255_0x00ff => -1,
+        // 0xffnn
+        EnumAu16::u65280_0xff00 => 0,
+        EnumAu16::u65407_0xff7f => 127,
+        EnumAu16::u65408_0xff80 => -128,
+        EnumAu16::u65535_0xffff => 1,
     }
 }
 
@@ -248,7 +606,8 @@ enum EnumAi128 {
 // EMIT_MIR matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff
 fn match_i128_u128(i: EnumAi128) -> u128 {
     // CHECK-LABEL: fn match_i128_u128(
-    // CHECK: switchInt
+    // CHECK-NOT: switchInt
+    // CHECK: return
     match i {
         EnumAi128::A => 1,
         EnumAi128::B => 2,
@@ -262,15 +621,34 @@ fn main() {
     let _ = foo(Some(()));
     let _ = bar(0);
     let _ = match_nested_if();
-    let _ = match_u8_i16(EnumAu8::A);
-    let _ = match_u8_i16_2(EnumAu8::A);
-    let _ = match_u8_i16_failed(EnumAu8::A);
-    let _ = match_u8_i16_fallback(1);
-    let _ = match_u8_u16(EnumBu8::A);
-    let _ = match_u8_u16_2(EnumBu8::A);
-    let _ = match_i8_i16(EnumAi8::A);
-    let _ = match_i8_i16_failed(EnumAi8::A);
-    let _ = match_i8_i16(EnumAi8::A);
-    let _ = match_i16_i8(EnumAi16::A);
+
+    let _: i8 = match_u8_i8(EnumAu8::u0_0x00);
+    let _: i8 = match_u8_i8_failed(EnumAu8::u0_0x00);
+    let _: (i8, i8) = match_u8_i8_2(EnumAu8::u0_0x00);
+    let _: (i8, i8) = match_u8_i8_2_failed(EnumAu8::u0_0x00);
+    let _: i8 = match_u8_i8_fallback(EnumAu8::u0_0x00);
+    let _: i8 = match_u8_i8_failed_len_1(EnumAu8::u0_0x00);
+    let _: i8 = match_u8_i8_failed_len_2(EnumAu8::u0_0x00);
+
+    let _: i16 = match_sext_i8_i16(EnumAi8::o0_0x00);
+    let _: i16 = match_sext_i8_i16_failed(EnumAi8::o0_0x00);
+    let _: u16 = match_sext_i8_u16(EnumAi8::o0_0x00);
+    let _: u16 = match_sext_i8_u16_failed(EnumAi8::o0_0x00);
+
+    let _: u16 = match_zext_u8_u16(EnumAu8::u0_0x00);
+    let _: u16 = match_zext_u8_u16_failed(EnumAu8::u0_0x00);
+    let _: i16 = match_zext_u8_i16(EnumAu8::u0_0x00);
+    let _: i16 = match_zext_u8_i16_failed(EnumAu8::u0_0x00);
+
+    let _: i8 = match_trunc_i16_i8(EnumAi16::o0_0x0000);
+    let _: i8 = match_trunc_i16_i8_failed(EnumAi16::o0_0x0000);
+    let _: u8 = match_trunc_i16_u8(EnumAi16::o0_0x0000);
+    let _: u8 = match_trunc_i16_u8_failed(EnumAi16::o0_0x0000);
+
+    let _: i8 = match_trunc_u16_i8(EnumAu16::u0_0x0000);
+    let _: i8 = match_trunc_u16_i8_failed(EnumAu16::u0_0x0000);
+    let _: u8 = match_trunc_u16_u8(EnumAu16::u0_0x0000);
+    let _: u8 = match_trunc_u16_u8_failed(EnumAu16::u0_0x0000);
+
     let _ = match_i128_u128(EnumAi128::A);
 }
diff --git a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
index 157f9c98353..11a18f58e3a 100644
--- a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
+++ b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
@@ -5,27 +5,32 @@
       debug e => _1;
       let mut _0: u8;
       let mut _2: isize;
++     let mut _3: isize;
   
       bb0: {
           _2 = discriminant(_1);
-          switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const 1_u8;
-          goto -> bb4;
-      }
-  
-      bb3: {
-          _0 = const 0_u8;
-          goto -> bb4;
-      }
-  
-      bb4: {
+-         switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 1_u8;
+-         goto -> bb4;
+-     }
+- 
+-     bb3: {
+-         _0 = const 0_u8;
+-         goto -> bb4;
+-     }
+- 
+-     bb4: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u8 (IntToInt);
++         StorageDead(_3);
           return;
       }
   }
diff --git a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
index 19083771fd9..809badc41ba 100644
--- a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
+++ b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
@@ -5,27 +5,32 @@
       debug e => _1;
       let mut _0: i8;
       let mut _2: isize;
++     let mut _3: isize;
   
       bb0: {
           _2 = discriminant(_1);
-          switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const 1_i8;
-          goto -> bb4;
-      }
-  
-      bb3: {
-          _0 = const 0_i8;
-          goto -> bb4;
-      }
-  
-      bb4: {
+-         switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 1_i8;
+-         goto -> bb4;
+-     }
+- 
+-     bb3: {
+-         _0 = const 0_i8;
+-         goto -> bb4;
+-     }
+- 
+-     bb4: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i8 (IntToInt);
++         StorageDead(_3);
           return;
       }
   }
diff --git a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff
index da7a2bd10e0..1e1ddfae0eb 100644
--- a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff
+++ b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff
@@ -19,14 +19,16 @@
   
       bb1: {
           _2 = discriminant(_1);
--         switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb2];
-+         _5 = Eq(_2, const 0_isize);
+-         switchInt(move _2) -> [1: bb3, otherwise: bb2];
++         _5 = Ne(_2, const 1_isize);
 +         assume(move _5);
-+         goto -> bb4;
++         goto -> bb2;
       }
   
       bb2: {
-          unreachable;
+          _0 = const ();
+          StorageDead(_1);
+          return;
       }
   
       bb3: {
@@ -35,11 +37,5 @@
 -         StorageLive(_4);
           unreachable;
       }
-  
-      bb4: {
-          _0 = const ();
-          StorageDead(_1);
-          return;
-      }
   }
   
diff --git a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff
index a2121fc684f..809d24aa15a 100644
--- a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff
+++ b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff
@@ -19,14 +19,16 @@
   
       bb1: {
           _2 = discriminant(_1);
--         switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb2];
-+         _5 = Eq(_2, const 0_isize);
+-         switchInt(move _2) -> [1: bb3, otherwise: bb2];
++         _5 = Ne(_2, const 1_isize);
 +         assume(move _5);
-+         goto -> bb4;
++         goto -> bb2;
       }
   
       bb2: {
-          unreachable;
+          _0 = const ();
+          StorageDead(_1);
+          return;
       }
   
       bb3: {
@@ -35,11 +37,5 @@
 -         StorageLive(_4);
           unreachable;
       }
-  
-      bb4: {
-          _0 = const ();
-          StorageDead(_1);
-          return;
-      }
   }
   
diff --git a/tests/mir-opt/unreachable.rs b/tests/mir-opt/unreachable.rs
index 881e3542f0a..f7f4815ae7c 100644
--- a/tests/mir-opt/unreachable.rs
+++ b/tests/mir-opt/unreachable.rs
@@ -45,18 +45,16 @@ fn as_match() {
     // CHECK: bb0: {
     // CHECK: {{_.*}} = empty()
     // CHECK: bb1: {
-    // CHECK: [[eq:_.*]] = Eq({{.*}}, const 0_isize);
+    // CHECK: [[eq:_.*]] = Ne({{.*}}, const 1_isize);
     // CHECK-NEXT: assume(move [[eq]]);
-    // CHECK-NEXT: goto -> bb4;
+    // CHECK-NEXT: goto -> bb2;
     // CHECK: bb2: {
-    // CHECK-NEXT: unreachable;
+    // CHECK: return;
     // CHECK: bb3: {
     // CHECK-NEXT: unreachable;
-    // CHECK: bb4: {
-    // CHECK: return;
     match empty() {
-        None => {}
         Some(_x) => match _x {},
+        None => {}
     }
 }
 
diff --git a/tests/mir-opt/unreachable_enum_branching.rs b/tests/mir-opt/unreachable_enum_branching.rs
index fac14042b10..7647f9bf077 100644
--- a/tests/mir-opt/unreachable_enum_branching.rs
+++ b/tests/mir-opt/unreachable_enum_branching.rs
@@ -49,7 +49,7 @@ struct Plop {
 fn simple() {
     // CHECK-LABEL: fn simple(
     // CHECK: [[discr:_.*]] = discriminant(
-    // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb2, otherwise: [[unreachable]]];
+    // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb1, otherwise: [[unreachable]]];
     // CHECK: [[unreachable]]: {
     // CHECK-NEXT: unreachable;
     match Test1::C {
diff --git a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
index 8aef9914936..5c08648fac3 100644
--- a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
@@ -14,40 +14,40 @@
           StorageLive(_2);
           _2 = Test1::C;
           _3 = discriminant(_2);
--         switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1];
-+         switchInt(move _3) -> [0: bb1, 1: bb1, 2: bb2, otherwise: bb1];
+-         switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
++         switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5];
       }
   
       bb1: {
-          unreachable;
-      }
-  
-      bb2: {
           StorageLive(_5);
           _5 = const "C";
           _1 = &(*_5);
           StorageDead(_5);
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb3: {
+      bb2: {
           StorageLive(_4);
           _4 = const "B(Empty)";
           _1 = &(*_4);
           StorageDead(_4);
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb4: {
+      bb3: {
           _1 = const "A(Empty)";
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb5: {
+      bb4: {
           StorageDead(_2);
           StorageDead(_1);
           _0 = const ();
           return;
++     }
++ 
++     bb5: {
++         unreachable;
       }
   }
   
diff --git a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
index 8aef9914936..5c08648fac3 100644
--- a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
@@ -14,40 +14,40 @@
           StorageLive(_2);
           _2 = Test1::C;
           _3 = discriminant(_2);
--         switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1];
-+         switchInt(move _3) -> [0: bb1, 1: bb1, 2: bb2, otherwise: bb1];
+-         switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
++         switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5];
       }
   
       bb1: {
-          unreachable;
-      }
-  
-      bb2: {
           StorageLive(_5);
           _5 = const "C";
           _1 = &(*_5);
           StorageDead(_5);
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb3: {
+      bb2: {
           StorageLive(_4);
           _4 = const "B(Empty)";
           _1 = &(*_4);
           StorageDead(_4);
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb4: {
+      bb3: {
           _1 = const "A(Empty)";
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb5: {
+      bb4: {
           StorageDead(_2);
           StorageDead(_1);
           _0 = const ();
           return;
++     }
++ 
++     bb5: {
++         unreachable;
       }
   }
   
diff --git a/tests/run-make/cdylib-dylib-linkage/Makefile b/tests/run-make/cdylib-dylib-linkage/Makefile
deleted file mode 100644
index db8393d3c05..00000000000
--- a/tests/run-make/cdylib-dylib-linkage/Makefile
+++ /dev/null
@@ -1,31 +0,0 @@
-# This test checks that cdylibs can link against dylibs as dependencies, after this restriction was disabled.
-# See https://github.com/rust-lang/rust/commit/72aaa3a414d17aa0c4f19feafa5bab5f84b60e63
-
-# ignore-cross-compile
-include ../tools.mk
-
-TARGET_SYSROOT := $(shell $(RUSTC) --print sysroot)/lib/rustlib/$(TARGET)/lib
-
-ifdef IS_MSVC
-LIBSTD := $(wildcard $(TARGET_SYSROOT)/libstd-*.dll.lib)
-else
-LIBSTD := $(wildcard $(TARGET_SYSROOT)/$(call DYLIB_GLOB,std))
-STD := $(basename $(patsubst lib%,%, $(notdir $(LIBSTD))))
-endif
-
-all: $(call RUN_BINFILE,foo)
-	$(call RUN,foo)
-
-ifdef IS_MSVC
-CLIBS := $(TMPDIR)/foo.dll.lib $(TMPDIR)/bar.dll.lib $(LIBSTD)
-$(call RUN_BINFILE,foo): $(call DYLIB,foo)
-	$(CC) $(CFLAGS) foo.c $(CLIBS) $(call OUT_EXE,foo)
-else
-CLIBS := -lfoo -lbar -l$(STD) -L $(TMPDIR) -L $(TARGET_SYSROOT)
-$(call RUN_BINFILE,foo): $(call DYLIB,foo)
-	$(CC) $(CFLAGS) foo.c $(CLIBS) -o $(call RUN_BINFILE,foo)
-endif
-
-$(call DYLIB,foo):
-	$(RUSTC) -C prefer-dynamic bar.rs
-	$(RUSTC) foo.rs
diff --git a/tests/run-make/cdylib-dylib-linkage/rmake.rs b/tests/run-make/cdylib-dylib-linkage/rmake.rs
new file mode 100644
index 00000000000..a8fd8e2d168
--- /dev/null
+++ b/tests/run-make/cdylib-dylib-linkage/rmake.rs
@@ -0,0 +1,41 @@
+// Previously, rustc mandated that cdylibs could only link against rlibs as dependencies,
+// making linkage between cdylibs and dylibs impossible. After this was changed in #68448,
+// this test attempts to link both `foo` (a cdylib) and `bar` (a dylib) and checks that
+// both compilation and execution are successful.
+// See https://github.com/rust-lang/rust/pull/68448
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{
+    bin_name, cc, dynamic_lib_extension, dynamic_lib_name, filename_contains, has_extension,
+    has_prefix, has_suffix, is_msvc, msvc_import_dynamic_lib_name, path, run, rustc,
+    shallow_find_files, target,
+};
+
+fn main() {
+    rustc().arg("-Cprefer-dynamic").input("bar.rs").run();
+    rustc().input("foo.rs").run();
+    let sysroot = rustc().print("sysroot").run().stdout_utf8();
+    let sysroot = sysroot.trim();
+    let target_sysroot = path(sysroot).join("lib/rustlib").join(target()).join("lib");
+    if is_msvc() {
+        let mut libs = shallow_find_files(&target_sysroot, |path| {
+            has_prefix(path, "libstd-") && has_suffix(path, ".dll.lib")
+        });
+        libs.push(path(msvc_import_dynamic_lib_name("foo")));
+        libs.push(path(msvc_import_dynamic_lib_name("bar")));
+        cc().input("foo.c").args(&libs).out_exe("foo").run();
+    } else {
+        let stdlibs = shallow_find_files(&target_sysroot, |path| {
+            has_extension(path, dynamic_lib_extension()) && filename_contains(path, "std")
+        });
+        cc().input("foo.c")
+            .args(&[dynamic_lib_name("foo"), dynamic_lib_name("bar")])
+            .arg(stdlibs.get(0).unwrap())
+            .library_search_path(&target_sysroot)
+            .output(bin_name("foo"))
+            .run();
+    }
+    run("foo");
+}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-1.rs b/tests/run-make/crate-loading/multiple-dep-versions-1.rs
new file mode 100644
index 00000000000..2d351633829
--- /dev/null
+++ b/tests/run-make/crate-loading/multiple-dep-versions-1.rs
@@ -0,0 +1,6 @@
+#![crate_name = "dependency"]
+#![crate_type = "rlib"]
+pub struct Type;
+pub trait Trait {}
+impl Trait for Type {}
+pub fn do_something<X: Trait>(_: X) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-2.rs b/tests/run-make/crate-loading/multiple-dep-versions-2.rs
new file mode 100644
index 00000000000..a5df3dc61ed
--- /dev/null
+++ b/tests/run-make/crate-loading/multiple-dep-versions-2.rs
@@ -0,0 +1,6 @@
+#![crate_name = "dependency"]
+#![crate_type = "rlib"]
+pub struct Type(pub i32);
+pub trait Trait {}
+impl Trait for Type {}
+pub fn do_something<X: Trait>(_: X) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs
new file mode 100644
index 00000000000..5a6cb03aaa4
--- /dev/null
+++ b/tests/run-make/crate-loading/multiple-dep-versions.rs
@@ -0,0 +1,8 @@
+extern crate dep_2_reexport;
+extern crate dependency;
+use dep_2_reexport::do_something;
+use dependency::Type;
+
+fn main() {
+    do_something(Type);
+}
diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs
new file mode 100644
index 00000000000..fd5b66ae879
--- /dev/null
+++ b/tests/run-make/crate-loading/rmake.rs
@@ -0,0 +1,27 @@
+//@ only-linux
+//@ ignore-wasm32
+//@ ignore-wasm64
+
+use run_make_support::rfs::copy;
+use run_make_support::{assert_contains, rust_lib_name, rustc};
+
+fn main() {
+    rustc().input("multiple-dep-versions-1.rs").run();
+    rustc().input("multiple-dep-versions-2.rs").extra_filename("2").metadata("2").run();
+
+    let out = rustc()
+        .input("multiple-dep-versions.rs")
+        .extern_("dependency", rust_lib_name("dependency"))
+        .extern_("dep_2_reexport", rust_lib_name("dependency2"))
+        .run_fail()
+        .assert_stderr_contains(
+            "you have multiple different versions of crate `dependency` in your dependency graph",
+        )
+        .assert_stderr_contains(
+            "two types coming from two different versions of the same crate are different types \
+             even if they look the same",
+        )
+        .assert_stderr_contains("this type doesn't implement the required trait")
+        .assert_stderr_contains("this type implements the required trait")
+        .assert_stderr_contains("this is the required trait");
+}
diff --git a/tests/run-make/cross-lang-lto-clang/Makefile b/tests/run-make/cross-lang-lto-clang/Makefile
deleted file mode 100644
index acf49c8f5c8..00000000000
--- a/tests/run-make/cross-lang-lto-clang/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-# needs-force-clang-based-tests
-
-# This test makes sure that cross-language inlining actually works by checking
-# the generated machine code.
-
-include ../tools.mk
-
-all: cpp-executable rust-executable
-
-cpp-executable:
-	$(RUSTC) -Clinker-plugin-lto=on -o $(TMPDIR)/librustlib-xlto.a -Copt-level=2 -Ccodegen-units=1 ./rustlib.rs
-	$(CLANG) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3
-	# Make sure we don't find a call instruction to the function we expect to
-	# always be inlined.
-	"$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined"
-	# As a sanity check, make sure we do find a call instruction to a
-	# non-inlined function
-	"$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined"
-
-rust-executable:
-	$(CLANG) ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2
-	(cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o)
-	$(RUSTC) -Clinker-plugin-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=$(CLANG) -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain
-	"$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined"
-	"$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined"
diff --git a/tests/run-make/cross-lang-lto-clang/rmake.rs b/tests/run-make/cross-lang-lto-clang/rmake.rs
new file mode 100644
index 00000000000..1b15a54aacb
--- /dev/null
+++ b/tests/run-make/cross-lang-lto-clang/rmake.rs
@@ -0,0 +1,62 @@
+// This test checks that cross-language inlining actually works by checking
+// the generated machine code.
+// See https://github.com/rust-lang/rust/pull/57514
+
+//@ needs-force-clang-based-tests
+// NOTE(#126180): This test only runs on `x86_64-gnu-debug`, because that CI job sets
+// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
+// name.
+
+use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, rustc, static_lib_name};
+
+fn main() {
+    rustc()
+        .linker_plugin_lto("on")
+        .output(static_lib_name("rustlib-xlto"))
+        .opt_level("2")
+        .codegen_units(1)
+        .input("rustlib.rs")
+        .run();
+    clang()
+        .lto("thin")
+        .use_ld("lld")
+        .arg("-lrustlib-xlto")
+        .out_exe("cmain")
+        .input("cmain.c")
+        .arg("-O3")
+        .run();
+    // Make sure we don't find a call instruction to the function we expect to
+    // always be inlined.
+    llvm_objdump()
+        .disassemble()
+        .input("cmain")
+        .run()
+        .assert_stdout_not_contains_regex("call.*rust_always_inlined");
+    // As a sanity check, make sure we do find a call instruction to a
+    // non-inlined function
+    llvm_objdump()
+        .disassemble()
+        .input("cmain")
+        .run()
+        .assert_stdout_contains_regex("call.*rust_never_inlined");
+    clang().input("clib.c").lto("thin").arg("-c").out_exe("clib.o").arg("-O2").run();
+    llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run();
+    rustc()
+        .linker_plugin_lto("on")
+        .opt_level("2")
+        .linker(&env_var("CLANG"))
+        .link_arg("-fuse-ld=lld")
+        .input("main.rs")
+        .output("rsmain")
+        .run();
+    llvm_objdump()
+        .disassemble()
+        .input("rsmain")
+        .run()
+        .assert_stdout_not_contains_regex("call.*c_always_inlined");
+    llvm_objdump()
+        .disassemble()
+        .input("rsmain")
+        .run()
+        .assert_stdout_contains_regex("call.*c_never_inlined");
+}
diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/clib.c b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/clib.c
index 90f33f24dc4..90f33f24dc4 100644
--- a/tests/run-make/cross-lang-lto-pgo-smoketest/clib.c
+++ b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/clib.c
diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/cmain.c b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/cmain.c
index e3f24828be3..e3f24828be3 100644
--- a/tests/run-make/cross-lang-lto-pgo-smoketest/cmain.c
+++ b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/cmain.c
diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/main.rs b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/main.rs
index 8129dcb85d9..8129dcb85d9 100644
--- a/tests/run-make/cross-lang-lto-pgo-smoketest/main.rs
+++ b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/main.rs
diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rmake.rs b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rmake.rs
new file mode 100644
index 00000000000..03c9af4bb89
--- /dev/null
+++ b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rmake.rs
@@ -0,0 +1,120 @@
+// This test makes sure that cross-language inlining can be used in conjunction
+// with profile-guided optimization. The test only tests that the whole workflow
+// can be executed without anything crashing. It does not test whether PGO or
+// xLTO have any specific effect on the generated code.
+// See https://github.com/rust-lang/rust/pull/61036
+
+//@ needs-force-clang-based-tests
+// NOTE(#126180): This test would only run on `x86_64-gnu-debug`, because that CI job sets
+// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
+// name.
+
+//@ needs-profiler-support
+// FIXME(Oneirical): Except that due to the reliance on llvm-profdata, this test
+// never runs, because `x86_64-gnu-debug` does not have the `profiler_builtins` crate.
+
+//FIXME(Oneirical): There was a strange workaround for MSVC on this test
+// which added -C panic=abort to every RUSTC call. It was justified as follows:
+
+// "LLVM doesn't support instrumenting binaries that use SEH:
+// https://bugs.llvm.org/show_bug.cgi?id=41279
+// Things work fine with -Cpanic=abort though."
+
+// This isn't very pertinent, however, as the test does not get run on any
+// MSVC platforms.
+
+use run_make_support::{
+    clang, env_var, has_extension, has_prefix, llvm_ar, llvm_profdata, rfs, run, rustc,
+    shallow_find_files, static_lib_name,
+};
+
+fn main() {
+    rustc()
+        .linker_plugin_lto("on")
+        .output(static_lib_name("rustlib-xlto"))
+        .opt_level("3")
+        .codegen_units(1)
+        .input("rustlib.rs")
+        .arg("-Cprofile-generate=cpp-profdata")
+        .run();
+    clang()
+        .lto("thin")
+        .arg("-fprofile-generate=cpp-profdata")
+        .use_ld("lld")
+        .arg("-lrustlib-xlto")
+        .out_exe("cmain")
+        .input("cmain.c")
+        .arg("-O3")
+        .run();
+    run("cmain");
+    // Postprocess the profiling data so it can be used by the compiler
+    let profraw_files = shallow_find_files("cpp-profdata", |path| {
+        has_prefix(path, "default") && has_extension(path, "profraw")
+    });
+    let profraw_file = profraw_files.get(0).unwrap();
+    llvm_profdata().merge().output("cpp-profdata/merged.profdata").input(profraw_file).run();
+    rustc()
+        .linker_plugin_lto("on")
+        .profile_use("cpp-profdata/merged.profdata")
+        .output(static_lib_name("rustlib-xlto"))
+        .opt_level("3")
+        .codegen_units(1)
+        .input("rustlib.rs")
+        .run();
+    clang()
+        .lto("thin")
+        .arg("-fprofile-use=cpp-profdata/merged.profdata")
+        .use_ld("lld")
+        .arg("-lrustlib-xlto")
+        .out_exe("cmain")
+        .input("cmain.c")
+        .arg("-O3")
+        .run();
+
+    clang()
+        .input("clib.c")
+        .arg("-fprofile-generate=rs-profdata")
+        .lto("thin")
+        .arg("-c")
+        .out_exe("clib.o")
+        .arg("-O3")
+        .run();
+    llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run();
+    rustc()
+        .linker_plugin_lto("on")
+        .opt_level("3")
+        .codegen_units(1)
+        .arg("-Cprofile-generate=rs-profdata")
+        .linker(&env_var("CLANG"))
+        .link_arg("-fuse-ld=lld")
+        .input("main.rs")
+        .output("rsmain")
+        .run();
+    run("rsmain");
+    // Postprocess the profiling data so it can be used by the compiler
+    let profraw_files = shallow_find_files("rs-profdata", |path| {
+        has_prefix(path, "default") && has_extension(path, "profraw")
+    });
+    let profraw_file = profraw_files.get(0).unwrap();
+    llvm_profdata().merge().output("rs-profdata/merged.profdata").input(profraw_file).run();
+    clang()
+        .input("clib.c")
+        .arg("-fprofile-use=rs-profdata/merged.profdata")
+        .arg("-c")
+        .lto("thin")
+        .out_exe("clib.o")
+        .arg("-O3")
+        .run();
+    rfs::remove_file(static_lib_name("xyz"));
+    llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run();
+    rustc()
+        .linker_plugin_lto("on")
+        .opt_level("3")
+        .codegen_units(1)
+        .arg("-Cprofile-use=rs-profdata/merged.profdata")
+        .linker(&env_var("CLANG"))
+        .link_arg("-fuse-ld=lld")
+        .input("main.rs")
+        .output("rsmain")
+        .run();
+}
diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/rustlib.rs b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rustlib.rs
index 9aff29ef9bb..9aff29ef9bb 100644
--- a/tests/run-make/cross-lang-lto-pgo-smoketest/rustlib.rs
+++ b/tests/run-make/cross-lang-lto-pgo-smoketest-clang/rustlib.rs
diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile b/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile
deleted file mode 100644
index 738e23f9c66..00000000000
--- a/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile
+++ /dev/null
@@ -1,90 +0,0 @@
-# needs-force-clang-based-tests
-
-# FIXME(#126180): This test doesn't actually run anywhere, because the only
-# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests.
-
-# This test makes sure that cross-language inlining can be used in conjunction
-# with profile-guided optimization. The test only tests that the whole workflow
-# can be executed without anything crashing. It does not test whether PGO or
-# xLTO have any specific effect on the generated code.
-
-include ../tools.mk
-
-COMMON_FLAGS=-Copt-level=3 -Ccodegen-units=1
-
-# LLVM doesn't support instrumenting binaries that use SEH:
-# https://bugs.llvm.org/show_bug.cgi?id=41279
-#
-# Things work fine with -Cpanic=abort though.
-ifdef IS_MSVC
-COMMON_FLAGS+= -Cpanic=abort
-endif
-
-all: cpp-executable rust-executable
-
-cpp-executable:
-	$(RUSTC) -Clinker-plugin-lto=on \
-	         -Cprofile-generate="$(TMPDIR)"/cpp-profdata \
-	         -o "$(TMPDIR)"/librustlib-xlto.a \
-	         $(COMMON_FLAGS) \
-	         ./rustlib.rs
-	$(CLANG) -flto=thin \
-	         -fprofile-generate="$(TMPDIR)"/cpp-profdata \
-	         -fuse-ld=lld \
-	         -L "$(TMPDIR)" \
-	         -lrustlib-xlto \
-	         -o "$(TMPDIR)"/cmain \
-	         -O3 \
-	         ./cmain.c
-	$(TMPDIR)/cmain
-	# Postprocess the profiling data so it can be used by the compiler
-	"$(LLVM_BIN_DIR)"/llvm-profdata merge \
-		-o "$(TMPDIR)"/cpp-profdata/merged.profdata \
-		"$(TMPDIR)"/cpp-profdata/default_*.profraw
-	$(RUSTC) -Clinker-plugin-lto=on \
-	         -Cprofile-use="$(TMPDIR)"/cpp-profdata/merged.profdata \
-	         -o "$(TMPDIR)"/librustlib-xlto.a \
-	         $(COMMON_FLAGS) \
-	         ./rustlib.rs
-	$(CLANG) -flto=thin \
-	         -fprofile-use="$(TMPDIR)"/cpp-profdata/merged.profdata \
-	         -fuse-ld=lld \
-	         -L "$(TMPDIR)" \
-	         -lrustlib-xlto \
-	         -o "$(TMPDIR)"/cmain \
-	         -O3 \
-	         ./cmain.c
-
-rust-executable:
-	exit
-	$(CLANG) ./clib.c -fprofile-generate="$(TMPDIR)"/rs-profdata -flto=thin -c -o $(TMPDIR)/clib.o -O3
-	(cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o)
-	$(RUSTC) -Clinker-plugin-lto=on \
-	         -Cprofile-generate="$(TMPDIR)"/rs-profdata \
-	         -L$(TMPDIR) \
-	         $(COMMON_FLAGS) \
-	         -Clinker=$(CLANG) \
-	         -Clink-arg=-fuse-ld=lld \
-	         -o $(TMPDIR)/rsmain \
-	         ./main.rs
-	$(TMPDIR)/rsmain
-	# Postprocess the profiling data so it can be used by the compiler
-	"$(LLVM_BIN_DIR)"/llvm-profdata merge \
-		-o "$(TMPDIR)"/rs-profdata/merged.profdata \
-		"$(TMPDIR)"/rs-profdata/default_*.profraw
-	$(CLANG) ./clib.c \
-	         -fprofile-use="$(TMPDIR)"/rs-profdata/merged.profdata \
-	         -flto=thin \
-	         -c \
-	         -o $(TMPDIR)/clib.o \
-	         -O3
-	rm "$(TMPDIR)"/libxyz.a
-	(cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o)
-	$(RUSTC) -Clinker-plugin-lto=on \
-	         -Cprofile-use="$(TMPDIR)"/rs-profdata/merged.profdata \
-	         -L$(TMPDIR) \
-	         $(COMMON_FLAGS) \
-	         -Clinker=$(CLANG) \
-	         -Clink-arg=-fuse-ld=lld \
-	         -o $(TMPDIR)/rsmain \
-	         ./main.rs
diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
index 391759ec5f6..92573353a74 100644
--- a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
+++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
@@ -3,8 +3,11 @@
 //@ needs-force-clang-based-tests
 //@ needs-llvm-components riscv
 
-// FIXME(#126180): This test doesn't actually run anywhere, because the only
-// CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests.
+//@ needs-force-clang-based-tests
+// FIXME(#126180): This test can only run on `x86_64-gnu-debug`, because that CI job sets
+// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
+// name.
+// However, this test does not run at all as its name does not contain "clang".
 
 use std::path::PathBuf;
 use std::process::{Command, Output};
diff --git a/tests/run-make/cross-lang-lto-upstream-rlibs/Makefile b/tests/run-make/cross-lang-lto-upstream-rlibs/Makefile
deleted file mode 100644
index 6f1caa31a80..00000000000
--- a/tests/run-make/cross-lang-lto-upstream-rlibs/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-include ../tools.mk
-
-# ignore windows due to libLLVM being present in PATH and the PATH and library path being the same
-# (so fixing it is harder). See #57765 for context
-ifndef IS_WINDOWS
-
-# This test makes sure that we don't loose upstream object files when compiling
-# staticlibs with -C linker-plugin-lto
-
-all: staticlib.rs upstream.rs
-	$(RUSTC) upstream.rs -C linker-plugin-lto -Ccodegen-units=1
-
-	# Check No LTO
-	$(RUSTC) staticlib.rs -C linker-plugin-lto -Ccodegen-units=1 -L. -o $(TMPDIR)/staticlib.a
-	(cd $(TMPDIR); "$(LLVM_BIN_DIR)"/llvm-ar x ./staticlib.a)
-	# Make sure the upstream object file was included
-	ls $(TMPDIR)/upstream.*.rcgu.o
-
-	# Cleanup
-	rm $(TMPDIR)/*
-
-	# Check ThinLTO
-	$(RUSTC) upstream.rs -C linker-plugin-lto -Ccodegen-units=1 -Clto=thin
-	$(RUSTC) staticlib.rs -C linker-plugin-lto -Ccodegen-units=1 -Clto=thin -L. -o $(TMPDIR)/staticlib.a
-	(cd $(TMPDIR); "$(LLVM_BIN_DIR)"/llvm-ar x ./staticlib.a)
-	ls $(TMPDIR)/upstream.*.rcgu.o
-
-else
-
-all:
-
-endif
diff --git a/tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs b/tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs
new file mode 100644
index 00000000000..f0b8fa75bee
--- /dev/null
+++ b/tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs
@@ -0,0 +1,57 @@
+// When using the flag -C linker-plugin-lto, static libraries could lose their upstream object
+// files during compilation. This bug was fixed in #53031, and this test compiles a staticlib
+// dependent on upstream, checking that the upstream object file still exists after no LTO and
+// thin LTO.
+// See https://github.com/rust-lang/rust/pull/53031
+
+use run_make_support::{
+    cwd, has_extension, has_prefix, has_suffix, llvm_ar, rfs, rustc, shallow_find_files,
+    static_lib_name,
+};
+
+fn main() {
+    // The test starts with no LTO enabled.
+    rustc().input("upstream.rs").arg("-Clinker-plugin-lto").codegen_units(1).run();
+    rustc()
+        .input("staticlib.rs")
+        .arg("-Clinker-plugin-lto")
+        .codegen_units(1)
+        .output(static_lib_name("staticlib"))
+        .run();
+    llvm_ar().extract().arg(static_lib_name("staticlib")).run();
+    // Ensure the upstream object file was included.
+    assert_eq!(
+        shallow_find_files(cwd(), |path| {
+            has_prefix(path, "upstream.") && has_suffix(path, ".rcgu.o")
+        })
+        .len(),
+        1
+    );
+    // Remove all output files that are not source Rust code for cleanup.
+    for file in shallow_find_files(cwd(), |path| !has_extension(path, "rs")) {
+        rfs::remove_file(file)
+    }
+
+    // Check it again, with Thin LTO.
+    rustc()
+        .input("upstream.rs")
+        .arg("-Clinker-plugin-lto")
+        .codegen_units(1)
+        .arg("-Clto=thin")
+        .run();
+    rustc()
+        .input("staticlib.rs")
+        .arg("-Clinker-plugin-lto")
+        .codegen_units(1)
+        .arg("-Clto=thin")
+        .output(static_lib_name("staticlib"))
+        .run();
+    llvm_ar().extract().arg(static_lib_name("staticlib")).run();
+    assert_eq!(
+        shallow_find_files(cwd(), |path| {
+            has_prefix(path, "upstream.") && has_suffix(path, ".rcgu.o")
+        })
+        .len(),
+        1
+    );
+}
diff --git a/tests/run-make/dos-device-input/rmake.rs b/tests/run-make/dos-device-input/rmake.rs
new file mode 100644
index 00000000000..dee3b86f095
--- /dev/null
+++ b/tests/run-make/dos-device-input/rmake.rs
@@ -0,0 +1,13 @@
+//@ only-windows
+// Reason: dos devices are a Windows thing
+
+use std::path::Path;
+
+use run_make_support::{rustc, static_lib_name};
+
+fn main() {
+    rustc().input(r"\\.\NUL").crate_type("staticlib").run();
+    rustc().input(r"\\?\NUL").crate_type("staticlib").run();
+
+    assert!(Path::new(&static_lib_name("rust_out")).exists());
+}
diff --git a/tests/run-make/dump-ice-to-disk/rmake.rs b/tests/run-make/dump-ice-to-disk/rmake.rs
index 2fb5c825064..260abf3aa6f 100644
--- a/tests/run-make/dump-ice-to-disk/rmake.rs
+++ b/tests/run-make/dump-ice-to-disk/rmake.rs
@@ -4,15 +4,19 @@
 // or full.
 // - Check that disabling ICE logging results in zero files created.
 // - Check that the ICE files contain some of the expected strings.
+// - exercise the -Zmetrics-dir nightly flag
+// - verify what happens when both the nightly flag and env variable are set
+// - test the RUST_BACKTRACE=0 behavior against the file creation
+
 // See https://github.com/rust-lang/rust/pull/108714
 
 use run_make_support::{cwd, has_extension, has_prefix, rfs, rustc, shallow_find_files};
 
 fn main() {
-    rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
+    rustc().env("RUSTC_ICE", cwd()).input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
     let default = get_text_from_ice(".").lines().count();
-    clear_ice_files();
 
+    clear_ice_files();
     rustc().env("RUSTC_ICE", cwd()).input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
     let ice_text = get_text_from_ice(cwd());
     let default_set = ice_text.lines().count();
@@ -25,7 +29,28 @@ fn main() {
         ice_files.first().and_then(|f| f.file_name()).and_then(|n| n.to_str()).unwrap();
     // Ensure that the ICE dump path doesn't contain `:`, because they cause problems on Windows.
     assert!(!ice_file_name.contains(":"), "{ice_file_name}");
+    assert_eq!(default, default_set);
+    assert!(default > 0);
+    // Some of the expected strings in an ICE file should appear.
+    assert!(content.contains("thread 'rustc' panicked at"));
+    assert!(content.contains("stack backtrace:"));
+
+    test_backtrace_short(default);
+    test_backtrace_full(default);
+    test_backtrace_disabled(default);
+
+    clear_ice_files();
+    // The ICE dump is explicitly disabled. Therefore, this should produce no files.
+    rustc().env("RUSTC_ICE", "0").input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
+    let ice_files = shallow_find_files(cwd(), |path| {
+        has_prefix(path, "rustc-ice") && has_extension(path, "txt")
+    });
+    assert!(ice_files.is_empty()); // There should be 0 ICE files.
+
+    metrics_dir(default);
+}
 
+fn test_backtrace_short(baseline: usize) {
     clear_ice_files();
     rustc()
         .env("RUSTC_ICE", cwd())
@@ -34,6 +59,11 @@ fn main() {
         .arg("-Ztreat-err-as-bug=1")
         .run_fail();
     let short = get_text_from_ice(cwd()).lines().count();
+    // backtrace length in dump shouldn't be changed by RUST_BACKTRACE
+    assert_eq!(short, baseline);
+}
+
+fn test_backtrace_full(baseline: usize) {
     clear_ice_files();
     rustc()
         .env("RUSTC_ICE", cwd())
@@ -42,23 +72,49 @@ fn main() {
         .arg("-Ztreat-err-as-bug=1")
         .run_fail();
     let full = get_text_from_ice(cwd()).lines().count();
+    // backtrace length in dump shouldn't be changed by RUST_BACKTRACE
+    assert_eq!(full, baseline);
+}
+
+fn test_backtrace_disabled(baseline: usize) {
     clear_ice_files();
+    rustc()
+        .env("RUSTC_ICE", cwd())
+        .input("lib.rs")
+        .env("RUST_BACKTRACE", "0")
+        .arg("-Ztreat-err-as-bug=1")
+        .run_fail();
+    let disabled = get_text_from_ice(cwd()).lines().count();
+    // backtrace length in dump shouldn't be changed by RUST_BACKTRACE
+    assert_eq!(disabled, baseline);
+}
 
-    // The ICE dump is explicitly disabled. Therefore, this should produce no files.
-    rustc().env("RUSTC_ICE", "0").input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
-    let ice_files = shallow_find_files(cwd(), |path| {
-        has_prefix(path, "rustc-ice") && has_extension(path, "txt")
-    });
-    assert!(ice_files.is_empty()); // There should be 0 ICE files.
+fn metrics_dir(baseline: usize) {
+    test_flag_only(baseline);
+    test_flag_and_env(baseline);
+}
 
-    // The line count should not change.
-    assert_eq!(short, default_set);
-    assert_eq!(short, default);
-    assert_eq!(full, default_set);
-    assert!(default > 0);
-    // Some of the expected strings in an ICE file should appear.
-    assert!(content.contains("thread 'rustc' panicked at"));
-    assert!(content.contains("stack backtrace:"));
+fn test_flag_only(baseline: usize) {
+    clear_ice_files();
+    let metrics_arg = format!("-Zmetrics-dir={}", cwd().display());
+    rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").arg(metrics_arg).run_fail();
+    let output = get_text_from_ice(cwd()).lines().count();
+    assert_eq!(output, baseline);
+}
+
+fn test_flag_and_env(baseline: usize) {
+    clear_ice_files();
+    let metrics_arg = format!("-Zmetrics-dir={}", cwd().display());
+    let real_dir = cwd().join("actually_put_ice_here");
+    rfs::create_dir(real_dir.clone());
+    rustc()
+        .input("lib.rs")
+        .env("RUSTC_ICE", real_dir.clone())
+        .arg("-Ztreat-err-as-bug=1")
+        .arg(metrics_arg)
+        .run_fail();
+    let output = get_text_from_ice(real_dir).lines().count();
+    assert_eq!(output, baseline);
 }
 
 fn clear_ice_files() {
diff --git a/tests/run-make/fmt-write-bloat/main.rs b/tests/run-make/fmt-write-bloat/main.rs
index e86c48014c3..6f206d6515a 100644
--- a/tests/run-make/fmt-write-bloat/main.rs
+++ b/tests/run-make/fmt-write-bloat/main.rs
@@ -5,7 +5,7 @@
 use core::fmt;
 use core::fmt::Write;
 
-#[link(name = "c")]
+#[cfg_attr(not(windows), link(name = "c"))]
 extern "C" {}
 
 struct Dummy;
diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs
index 4ae226ec0e2..6875ef9ddc0 100644
--- a/tests/run-make/fmt-write-bloat/rmake.rs
+++ b/tests/run-make/fmt-write-bloat/rmake.rs
@@ -15,9 +15,12 @@
 //! `NO_DEBUG_ASSERTIONS=1`). If debug assertions are disabled, then we can check for the absence of
 //! additional `usize` formatting and padding related symbols.
 
-// Reason: This test is `ignore-windows` because the `no_std` test (using `#[link(name = "c")])`
-// doesn't link on windows.
 //@ ignore-windows
+// Reason:
+// - MSVC targets really need to parse the .pdb file (aka the debug information).
+//   On Windows there's an API for that (dbghelp) which maybe we can use
+// - MinGW targets have a lot of symbols included in their runtime which we can't avoid.
+//   We would need to make the symbols we're looking for more specific for this test to work.
 //@ ignore-cross-compile
 
 use run_make_support::env::no_debug_assertions;
diff --git a/tests/run-make/issue-88756-default-output/Makefile b/tests/run-make/issue-88756-default-output/Makefile
deleted file mode 100644
index d1c3d0fe082..00000000000
--- a/tests/run-make/issue-88756-default-output/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
-	$(BARE_RUSTDOC) 2>&1 | sed -E 's@/nightly/|/beta/|/stable/|/1\.[0-9]+\.[0-9]+/@/$$CHANNEL/@g' | diff - output-default.stdout
diff --git a/tests/run-make/issue-88756-default-output/README.md b/tests/run-make/issue-88756-default-output/README.md
deleted file mode 100644
index 8cbfac4f7d2..00000000000
--- a/tests/run-make/issue-88756-default-output/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This is a test to verify that the default behavior of `rustdoc` is printing out help output instead of erroring out (#88756).
diff --git a/tests/run-make/issue-88756-default-output/x.rs b/tests/run-make/issue-88756-default-output/x.rs
deleted file mode 100644
index 5df7576133a..00000000000
--- a/tests/run-make/issue-88756-default-output/x.rs
+++ /dev/null
@@ -1 +0,0 @@
-// nothing to see here
diff --git a/tests/run-make/link-args-order/rmake.rs b/tests/run-make/link-args-order/rmake.rs
index d238ad23f27..b7ef8333267 100644
--- a/tests/run-make/link-args-order/rmake.rs
+++ b/tests/run-make/link-args-order/rmake.rs
@@ -3,15 +3,14 @@
 // checks that linker arguments remain intact and in the order they were originally passed in.
 // See https://github.com/rust-lang/rust/pull/70665
 
-//@ ignore-msvc
-// Reason: the ld linker does not exist on Windows.
-
-use run_make_support::rustc;
+use run_make_support::{is_msvc, rustc};
 
 fn main() {
+    let linker = if is_msvc() { "msvc" } else { "ld" };
+
     rustc()
         .input("empty.rs")
-        .linker_flavor("ld")
+        .linker_flavor(linker)
         .link_arg("a")
         .link_args("b c")
         .link_args("d e")
@@ -20,7 +19,7 @@ fn main() {
         .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
     rustc()
         .input("empty.rs")
-        .linker_flavor("ld")
+        .linker_flavor(linker)
         .arg("-Zpre-link-arg=a")
         .arg("-Zpre-link-args=b c")
         .arg("-Zpre-link-args=d e")
diff --git a/tests/run-make/link-cfg/Makefile b/tests/run-make/link-cfg/Makefile
deleted file mode 100644
index a4099701144..00000000000
--- a/tests/run-make/link-cfg/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call DYLIB,return1) $(call DYLIB,return2) $(call NATIVE_STATICLIB,return3)
-	ls $(TMPDIR)
-	$(BARE_RUSTC) --print cfg --target x86_64-unknown-linux-musl | $(CGREP) crt-static
-
-	$(RUSTC) no-deps.rs --cfg foo
-	$(call RUN,no-deps)
-	$(RUSTC) no-deps.rs --cfg bar
-	$(call RUN,no-deps)
-
-	$(RUSTC) dep.rs
-	$(RUSTC) with-deps.rs --cfg foo
-	$(call RUN,with-deps)
-	$(RUSTC) with-deps.rs --cfg bar
-	$(call RUN,with-deps)
-
-	$(RUSTC) dep-with-staticlib.rs
-	$(RUSTC) with-staticlib-deps.rs --cfg foo
-	$(call RUN,with-staticlib-deps)
-	$(RUSTC) with-staticlib-deps.rs --cfg bar
-	$(call RUN,with-staticlib-deps)
diff --git a/tests/run-make/link-cfg/rmake.rs b/tests/run-make/link-cfg/rmake.rs
new file mode 100644
index 00000000000..732de5dbd0b
--- /dev/null
+++ b/tests/run-make/link-cfg/rmake.rs
@@ -0,0 +1,43 @@
+// The `#[link(cfg(..))]` annotation means that the `#[link]`
+// directive is only active in a compilation unit if that `cfg` value is satisfied.
+// For example, when compiling an rlib, these directives are just encoded and
+// ignored for dylibs, and all staticlibs are continued to be put into the rlib as
+// usual. When placing that rlib into a staticlib, executable, or dylib, however,
+// the `cfg` is evaluated *as if it were defined in the final artifact* and the
+// library is decided to be linked or not.
+// This test exercises this new feature by testing it with no dependencies, then
+// with only dynamic libraries, then with both a staticlib and dylibs. Compilation
+// and execution should be successful.
+// See https://github.com/rust-lang/rust/pull/37545
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{bare_rustc, build_native_dynamic_lib, build_native_static_lib, run, rustc};
+
+fn main() {
+    build_native_dynamic_lib("return1");
+    build_native_dynamic_lib("return2");
+    build_native_static_lib("return3");
+    bare_rustc()
+        .print("cfg")
+        .target("x86_64-unknown-linux-musl")
+        .run()
+        .assert_stdout_contains("crt-static");
+    rustc().input("no-deps.rs").cfg("foo").run();
+    run("no-deps");
+    rustc().input("no-deps.rs").cfg("bar").run();
+    run("no-deps");
+
+    rustc().input("dep.rs").run();
+    rustc().input("with-deps.rs").cfg("foo").run();
+    run("with-deps");
+    rustc().input("with-deps.rs").cfg("bar").run();
+    run("with-deps");
+
+    rustc().input("dep-with-staticlib.rs").run();
+    rustc().input("with-staticlib-deps.rs").cfg("foo").run();
+    run("with-staticlib-deps");
+    rustc().input("with-staticlib-deps.rs").cfg("bar").run();
+    run("with-staticlib-deps");
+}
diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs
index 9bff3a4b44c..6075f310954 100644
--- a/tests/run-make/link-dedup/rmake.rs
+++ b/tests/run-make/link-dedup/rmake.rs
@@ -5,20 +5,37 @@
 // Without the --cfg flag, there should be a single -ltesta, no more, no less.
 // See https://github.com/rust-lang/rust/pull/84794
 
-//@ ignore-msvc
+use std::fmt::Write;
 
-use run_make_support::rustc;
+use run_make_support::{is_msvc, rustc};
 
 fn main() {
     rustc().input("depa.rs").run();
     rustc().input("depb.rs").run();
     rustc().input("depc.rs").run();
+
     let output = rustc().input("empty.rs").cfg("bar").run_fail();
-    output.assert_stderr_contains(r#""-ltesta" "-ltestb" "-ltesta""#);
-    let output = rustc().input("empty.rs").run_fail();
-    output.assert_stderr_contains(r#""-ltesta""#);
-    let output = rustc().input("empty.rs").run_fail();
-    output.assert_stderr_not_contains(r#""-ltestb""#);
+    output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));
+
     let output = rustc().input("empty.rs").run_fail();
-    output.assert_stderr_not_contains(r#""-ltesta" "-ltesta" "-ltesta""#);
+    output.assert_stderr_contains(needle_from_libs(&["testa"]));
+    output.assert_stderr_not_contains(needle_from_libs(&["testb"]));
+    output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
+    // Adjacent identical native libraries are no longer deduplicated if
+    // they come from different crates (https://github.com/rust-lang/rust/pull/103311)
+    // so the following will fail:
+    //output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa"]));
+}
+
+fn needle_from_libs(libs: &[&str]) -> String {
+    let mut needle = String::new();
+    for lib in libs {
+        if is_msvc() {
+            let _ = needle.write_fmt(format_args!(r#""{lib}.lib" "#));
+        } else {
+            let _ = needle.write_fmt(format_args!(r#""-l{lib}" "#));
+        }
+    }
+    needle.pop(); // remove trailing space
+    needle
 }
diff --git a/tests/run-make/long-linker-command-lines-cmd-exe/Makefile b/tests/run-make/long-linker-command-lines-cmd-exe/Makefile
deleted file mode 100644
index e43aab7f8e0..00000000000
--- a/tests/run-make/long-linker-command-lines-cmd-exe/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) foo.rs -g
-	cp foo.bat $(TMPDIR)/
-	OUT_DIR="$(TMPDIR)" RUSTC="$(RUSTC_ORIGINAL)" $(call RUN,foo)
diff --git a/tests/run-make/long-linker-command-lines-cmd-exe/foo.rs b/tests/run-make/long-linker-command-lines-cmd-exe/foo.rs
index 1d5202dcdb4..a28cc7909fe 100644
--- a/tests/run-make/long-linker-command-lines-cmd-exe/foo.rs
+++ b/tests/run-make/long-linker-command-lines-cmd-exe/foo.rs
@@ -1,16 +1,3 @@
-// Like the `long-linker-command-lines` test this test attempts to blow
-// a command line limit for running the linker. Unlike that test, however,
-// this test is testing `cmd.exe` specifically rather than the OS.
-//
-// Unfortunately `cmd.exe` has a 8192 limit which is relatively small
-// in the grand scheme of things and anyone sripting rustc's linker
-// is probably using a `*.bat` script and is likely to hit this limit.
-//
-// This test uses a `foo.bat` script as the linker which just simply
-// delegates back to this program. The compiler should use a lower
-// limit for arguments before passing everything via `@`, which
-// means that everything should still succeed here.
-
 use std::env;
 use std::fs::{self, File};
 use std::io::{BufWriter, Read, Write};
@@ -18,13 +5,8 @@ use std::path::PathBuf;
 use std::process::Command;
 
 fn main() {
-    if !cfg!(windows) {
-        return;
-    }
-
-    let tmpdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
-    let ok = tmpdir.join("ok");
-    let not_ok = tmpdir.join("not_ok");
+    let ok = PathBuf::from("ok");
+    let not_ok = PathBuf::from("not_ok");
     if env::var("YOU_ARE_A_LINKER").is_ok() {
         match env::args_os().find(|a| a.to_string_lossy().contains("@")) {
             Some(file) => {
@@ -45,7 +27,7 @@ fn main() {
     for i in (1..).map(|i| i * 10) {
         println!("attempt: {}", i);
 
-        let file = tmpdir.join("bar.rs");
+        let file = PathBuf::from("bar.rs");
         let mut f = BufWriter::new(File::create(&file).unwrap());
         let mut lib_name = String::new();
         for _ in 0..i {
@@ -63,8 +45,6 @@ fn main() {
             .arg(&file)
             .arg("-C")
             .arg(&bat_linker)
-            .arg("--out-dir")
-            .arg(&tmpdir)
             .env("YOU_ARE_A_LINKER", "1")
             .env("MY_LINKER", &me)
             .status()
diff --git a/tests/run-make/long-linker-command-lines-cmd-exe/rmake.rs b/tests/run-make/long-linker-command-lines-cmd-exe/rmake.rs
new file mode 100644
index 00000000000..60ed2c5bcd2
--- /dev/null
+++ b/tests/run-make/long-linker-command-lines-cmd-exe/rmake.rs
@@ -0,0 +1,26 @@
+// Like the `long-linker-command-lines` test this test attempts to blow
+// a command line limit for running the linker. Unlike that test, however,
+// this test is testing `cmd.exe` specifically rather than the OS.
+//
+// Unfortunately, the maximum length of the string that you can use at the
+// command prompt (`cmd.exe`) is 8191 characters.
+// Anyone scripting rustc's linker
+// is probably using a `*.bat` script and is likely to hit this limit.
+//
+// This test uses a `foo.bat` script as the linker which just simply
+// delegates back to this program. The compiler should use a lower
+// limit for arguments before passing everything via `@`, which
+// means that everything should still succeed here.
+// See https://github.com/rust-lang/rust/pull/47507
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+//@ only-windows
+// Reason: this test is specific to Windows executables
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    rustc().input("foo.rs").arg("-g").run();
+    run("foo");
+}
diff --git a/tests/run-make/long-linker-command-lines/Makefile b/tests/run-make/long-linker-command-lines/Makefile
deleted file mode 100644
index b573038e344..00000000000
--- a/tests/run-make/long-linker-command-lines/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-export LD_LIBRARY_PATH := $(HOST_RPATH_DIR)
-
-all:
-	$(RUSTC) foo.rs -g -O
-	RUSTC="$(RUSTC_ORIGINAL)" $(call RUN,foo)
diff --git a/tests/run-make/long-linker-command-lines/foo.rs b/tests/run-make/long-linker-command-lines/foo.rs
index 9d4a701ad87..5b30c06fac9 100644
--- a/tests/run-make/long-linker-command-lines/foo.rs
+++ b/tests/run-make/long-linker-command-lines/foo.rs
@@ -1,12 +1,3 @@
-// This is a test which attempts to blow out the system limit with how many
-// arguments can be passed to a process. This'll successively call rustc with
-// larger and larger argument lists in an attempt to find one that's way too
-// big for the system at hand. This file itself is then used as a "linker" to
-// detect when the process creation succeeds.
-//
-// Eventually we should see an argument that looks like `@` as we switch from
-// passing literal arguments to passing everything in the file.
-
 use std::collections::HashSet;
 use std::env;
 use std::fs::{self, File};
@@ -43,8 +34,7 @@ fn read_linker_args(path: &Path) -> String {
 }
 
 fn main() {
-    let tmpdir = PathBuf::from(env::var_os("TMPDIR").unwrap());
-    let ok = tmpdir.join("ok");
+    let ok = PathBuf::from("ok");
     if env::var("YOU_ARE_A_LINKER").is_ok() {
         if let Some(file) = env::args_os().find(|a| a.to_string_lossy().contains("@")) {
             let file = file.to_str().expect("non-utf8 file argument");
@@ -53,11 +43,11 @@ fn main() {
         return;
     }
 
-    let rustc = env::var_os("RUSTC").unwrap_or("rustc".into());
+    let rustc = env::var_os("RUSTC").unwrap();
     let me_as_linker = format!("linker={}", env::current_exe().unwrap().display());
     for i in (1..).map(|i| i * 100) {
         println!("attempt: {}", i);
-        let file = tmpdir.join("bar.rs");
+        let file = PathBuf::from("bar.rs");
         let mut expected_libs = write_test_case(&file, i);
 
         drop(fs::remove_file(&ok));
@@ -65,8 +55,6 @@ fn main() {
             .arg(&file)
             .arg("-C")
             .arg(&me_as_linker)
-            .arg("--out-dir")
-            .arg(&tmpdir)
             .env("YOU_ARE_A_LINKER", "1")
             .output()
             .unwrap();
diff --git a/tests/run-make/long-linker-command-lines/rmake.rs b/tests/run-make/long-linker-command-lines/rmake.rs
new file mode 100644
index 00000000000..e832d7f03e2
--- /dev/null
+++ b/tests/run-make/long-linker-command-lines/rmake.rs
@@ -0,0 +1,19 @@
+// This is a test which attempts to blow out the system limit with how many
+// arguments can be passed to a process. This'll successively call rustc with
+// larger and larger argument lists in an attempt to find one that's way too
+// big for the system at hand. This file itself is then used as a "linker" to
+// detect when the process creation succeeds.
+//
+// Eventually we should see an argument that looks like `@` as we switch from
+// passing literal arguments to passing everything in the file.
+// See https://github.com/rust-lang/rust/issues/41190
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    rustc().input("foo.rs").arg("-g").opt().run();
+    run("foo");
+}
diff --git a/tests/run-make/mte-ffi/bar.h b/tests/run-make/mte-ffi/bar.h
new file mode 100644
index 00000000000..a2292ae02a3
--- /dev/null
+++ b/tests/run-make/mte-ffi/bar.h
@@ -0,0 +1,43 @@
+#ifndef __BAR_H
+#define __BAR_H
+
+#include <sys/mman.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+// Set the allocation tag on the destination address using the STG instruction.
+#define set_tag(tagged_addr) do {                                      \
+    asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \
+} while (0)
+
+int mte_enabled() {
+    return (getauxval(AT_HWCAP2)) & HWCAP2_MTE;
+}
+
+void *alloc_page() {
+    // Enable MTE with synchronous checking
+    if (prctl(PR_SET_TAGGED_ADDR_CTRL,
+              PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | (0xfffe << PR_MTE_TAG_SHIFT),
+              0, 0, 0))
+    {
+        perror("prctl() failed");
+    }
+
+    // Using `mmap` allows us to ensure that, on systems which support MTE, the allocated
+    // memory is 16-byte aligned for MTE.
+    // This also allows us to explicitly specify whether the region should be protected by
+    // MTE or not.
+    if (mte_enabled()) {
+        void *ptr = mmap(NULL, sysconf(_SC_PAGESIZE),
+                         PROT_READ | PROT_WRITE | PROT_MTE, MAP_PRIVATE | MAP_ANONYMOUS,
+                         -1, 0);
+    } else {
+        void *ptr = mmap(NULL, sysconf(_SC_PAGESIZE),
+                         PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
+                         -1, 0);
+    }
+}
+
+#endif // __BAR_H
diff --git a/tests/run-make/mte-ffi/bar_float.c b/tests/run-make/mte-ffi/bar_float.c
new file mode 100644
index 00000000000..a1590f62765
--- /dev/null
+++ b/tests/run-make/mte-ffi/bar_float.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "bar.h"
+
+extern void foo(char*);
+
+void bar(char *ptr) {
+    if (((uintptr_t)ptr >> 56) != 0x1f) {
+        fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n");
+        exit(1);
+    }
+}
+
+int main(void)
+{
+    float *ptr = alloc_page();
+    if (ptr == MAP_FAILED)
+    {
+        perror("mmap() failed");
+        return EXIT_FAILURE;
+    }
+
+    // Store an arbitrary tag in bits 56-59 of the pointer (where an MTE tag may be),
+    // and a different value in the ignored top 4 bits.
+    ptr = (float *)((uintptr_t)ptr | 0x1fl << 56);
+
+    if (mte_enabled()) {
+        set_tag(ptr);
+    }
+
+    ptr[0] = 2.0f;
+    ptr[1] = 1.5f;
+
+    foo(ptr); // should change the contents of the page and call `bar`
+
+    if (ptr[0] != 0.5f || ptr[1] != 0.2f) {
+        fprintf(stderr, "invalid data in memory; expected '0.5 0.2', got '%f %f'\n",
+                ptr[0], ptr[1]);
+        return EXIT_FAILURE;
+    }
+
+    return 0;
+}
diff --git a/tests/run-make/mte-ffi/bar_function.c b/tests/run-make/mte-ffi/bar_function.c
new file mode 100644
index 00000000000..1fa48d32a0c
--- /dev/null
+++ b/tests/run-make/mte-ffi/bar_function.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "bar.h"
+
+typedef void (*fp)(int (*)());
+
+extern void foo(fp);
+
+void bar(int (*ptr)()) {
+    if (((uintptr_t)ptr >> 56) != 0x2f) {
+        fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n");
+        exit(1);
+    }
+
+    int r = (*ptr)();
+    if (r != 32) {
+        fprintf(stderr, "invalid return value; expected 32, got '%d'\n", r);
+        exit(1);
+    }
+}
+
+int main(void)
+{
+    fp ptr = alloc_page();
+    if (ptr == MAP_FAILED)
+    {
+        perror("mmap() failed");
+        return EXIT_FAILURE;
+    }
+
+    // Store an arbitrary tag in bits 56-59 of the pointer (where an MTE tag may be),
+    // and a different value in the ignored top 4 bits.
+    ptr = (fp)((uintptr_t)&bar | 0x1fl << 56);
+
+    foo(ptr);
+
+    return 0;
+}
diff --git a/tests/run-make/mte-ffi/bar_int.c b/tests/run-make/mte-ffi/bar_int.c
new file mode 100644
index 00000000000..d1c79e95dc9
--- /dev/null
+++ b/tests/run-make/mte-ffi/bar_int.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "bar.h"
+
+extern void foo(unsigned int *);
+
+void bar(char *ptr) {
+    if (((uintptr_t)ptr >> 56) != 0x1f) {
+        fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n");
+        exit(1);
+    }
+}
+
+int main(void)
+{
+    // Construct a pointer with an arbitrary tag in bits 56-59, simulating an MTE tag.
+    // It's only necessary that the tag is preserved across FFI bounds for this test.
+    unsigned int *ptr;
+
+    ptr = alloc_page();
+    if (ptr == MAP_FAILED)
+    {
+        perror("mmap() failed");
+        return EXIT_FAILURE;
+    }
+
+    // Store an arbitrary tag in bits 56-59 of the pointer (where an MTE tag may be),
+    // and a different value in the ignored top 4 bits.
+    ptr = (unsigned int *)((uintptr_t)ptr | 0x1fl << 56);
+
+    if (mte_enabled()) {
+        set_tag(ptr);
+    }
+
+    ptr[0] = 61;
+    ptr[1] = 62;
+
+    foo(ptr); // should change the contents of the page to start with 0x63 0x64 and call `bar`
+
+    if (ptr[0] != 0x63 || ptr[1] != 0x64) {
+        fprintf(stderr, "invalid data in memory; expected '63 64', got '%d %d'\n", ptr[0], ptr[1]);
+        return EXIT_FAILURE;
+    }
+
+    return 0;
+}
diff --git a/tests/run-make/mte-ffi/bar_string.c b/tests/run-make/mte-ffi/bar_string.c
new file mode 100644
index 00000000000..5669ffd6695
--- /dev/null
+++ b/tests/run-make/mte-ffi/bar_string.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "bar.h"
+
+extern void foo(char*);
+
+void bar(char *ptr) {
+    if (((uintptr_t)ptr >> 56) != 0x2f) {
+        fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n");
+        exit(1);
+    }
+
+    if (strcmp(ptr, "cd")) {
+        fprintf(stderr, "invalid data in memory; expected 'cd', got '%s'\n", ptr);
+        exit(1);
+    }
+}
+
+int main(void)
+{
+    // Construct a pointer with an arbitrary tag in bits 56-59, simulating an MTE tag.
+    // It's only necessary that the tag is preserved across FFI bounds for this test.
+    char *ptr;
+
+    ptr = alloc_page();
+    if (ptr == MAP_FAILED)
+    {
+        perror("mmap() failed");
+        return EXIT_FAILURE;
+    }
+
+    // Store an arbitrary tag in bits 56-59 of the pointer (where an MTE tag may be),
+    // and a different value in the ignored top 4 bits.
+    ptr = (unsigned int *)((uintptr_t)ptr | 0x1fl << 56);
+
+    if (mte_enabled()) {
+        set_tag(ptr);
+    }
+
+    ptr[0] = 'a';
+    ptr[1] = 'b';
+    ptr[2] = '\0';
+
+    foo(ptr);
+
+    return 0;
+}
diff --git a/tests/run-make/mte-ffi/foo_float.rs b/tests/run-make/mte-ffi/foo_float.rs
new file mode 100644
index 00000000000..c1bedd52494
--- /dev/null
+++ b/tests/run-make/mte-ffi/foo_float.rs
@@ -0,0 +1,19 @@
+#![crate_type = "cdylib"]
+#![crate_name = "foo"]
+
+use std::os::raw::c_float;
+
+extern "C" {
+    fn bar(ptr: *const c_float);
+}
+
+#[no_mangle]
+pub extern "C" fn foo(ptr: *mut c_float) {
+    assert_eq!((ptr as usize) >> 56, 0x1f);
+
+    unsafe {
+        *ptr = 0.5;
+        *ptr.wrapping_add(1) = 0.2;
+        bar(ptr);
+    }
+}
diff --git a/tests/run-make/mte-ffi/foo_function.rs b/tests/run-make/mte-ffi/foo_function.rs
new file mode 100644
index 00000000000..2c8e0b26238
--- /dev/null
+++ b/tests/run-make/mte-ffi/foo_function.rs
@@ -0,0 +1,17 @@
+#![crate_type = "cdylib"]
+#![crate_name = "foo"]
+
+extern "C" fn ret32() -> i32 {
+    32
+}
+
+#[no_mangle]
+pub extern "C" fn foo(ptr: extern "C" fn(extern "C" fn() -> i32)) {
+    assert_eq!((ptr as usize) >> 56, 0x1f);
+
+    // Store an arbitrary tag in the tag bits, and convert back to the correct pointer type.
+    let p = ((ret32 as usize) | (0x2f << 56)) as *const ();
+    let p: extern "C" fn() -> i32 = unsafe { std::mem::transmute(p) };
+
+    unsafe { ptr(p) }
+}
diff --git a/tests/run-make/mte-ffi/foo_int.rs b/tests/run-make/mte-ffi/foo_int.rs
new file mode 100644
index 00000000000..106d863cb81
--- /dev/null
+++ b/tests/run-make/mte-ffi/foo_int.rs
@@ -0,0 +1,19 @@
+#![crate_type = "cdylib"]
+#![crate_name = "foo"]
+
+use std::os::raw::c_uint;
+
+extern "C" {
+    fn bar(ptr: *const c_uint);
+}
+
+#[no_mangle]
+pub extern "C" fn foo(ptr: *mut c_uint) {
+    assert_eq!((ptr as usize) >> 56, 0x1f);
+
+    unsafe {
+        *ptr = 0x63;
+        *ptr.wrapping_add(1) = 0x64;
+        bar(ptr);
+    }
+}
diff --git a/tests/run-make/mte-ffi/foo_string.rs b/tests/run-make/mte-ffi/foo_string.rs
new file mode 100644
index 00000000000..54744802448
--- /dev/null
+++ b/tests/run-make/mte-ffi/foo_string.rs
@@ -0,0 +1,27 @@
+#![crate_type = "cdylib"]
+#![crate_name = "foo"]
+
+use std::arch::asm;
+use std::ffi::{CStr, CString};
+use std::os::raw::c_char;
+
+extern "C" {
+    fn bar(ptr: *const c_char);
+}
+
+#[no_mangle]
+pub extern "C" fn foo(ptr: *const c_char) {
+    assert_eq!((ptr as usize) >> 56, 0x1f);
+
+    let s = unsafe { CStr::from_ptr(ptr) };
+    assert_eq!(s.to_str().unwrap(), "ab");
+
+    let s = CString::from_vec_with_nul("cd\0".into()).unwrap();
+    let mut p = ((s.as_ptr() as usize) | (0x2f << 56)) as *const c_char;
+    unsafe {
+        #[cfg(target_feature = "mte")]
+        asm!("stg {p}, [{p}]", p = inout(reg) p);
+
+        bar(p);
+    }
+}
diff --git a/tests/run-make/mte-ffi/rmake.rs b/tests/run-make/mte-ffi/rmake.rs
new file mode 100644
index 00000000000..f4fafb796e3
--- /dev/null
+++ b/tests/run-make/mte-ffi/rmake.rs
@@ -0,0 +1,38 @@
+// Tests that MTE tags and values stored in the top byte of a pointer (TBI) are
+// preserved across FFI boundaries (C <-> Rust).
+// This test does not require MTE: whilst the test will use MTE if available, if it is not,
+// arbitrary tag bits are set using TBI.
+
+// This test is only valid for AArch64.
+// The linker must be explicitly specified when cross-compiling, so it is limited to
+// `aarch64-unknown-linux-gnu`.
+//@ only-aarch64-unknown-linux-gnu
+
+use run_make_support::{cc, dynamic_lib_name, extra_c_flags, run, rustc, target};
+
+fn main() {
+    run_test("int");
+    run_test("float");
+    run_test("string");
+    run_test("function");
+}
+
+fn run_test(variant: &str) {
+    let flags = {
+        let mut flags = extra_c_flags();
+        flags.push("-march=armv8.5-a+memtag");
+        flags
+    };
+    println!("{variant} test...");
+    rustc()
+        .input(format!("foo_{variant}.rs"))
+        .target(target())
+        .linker("aarch64-linux-gnu-gcc")
+        .run();
+    cc().input(format!("bar_{variant}.c"))
+        .input(dynamic_lib_name("foo"))
+        .out_exe("test")
+        .args(&flags)
+        .run();
+    run("test");
+}
diff --git a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
new file mode 100644
index 00000000000..f00123f006b
--- /dev/null
+++ b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
@@ -0,0 +1,89 @@
+#![feature(naked_functions, asm_const, linkage)]
+#![crate_type = "dylib"]
+
+use std::arch::asm;
+
+pub trait TraitWithConst {
+    const COUNT: u32;
+}
+
+struct Test;
+
+impl TraitWithConst for Test {
+    const COUNT: u32 = 1;
+}
+
+#[no_mangle]
+fn entry() {
+    private_vanilla();
+    private_naked();
+
+    public_vanilla_generic::<Test>();
+    public_naked_generic::<Test>();
+}
+
+extern "C" fn private_vanilla() -> u32 {
+    42
+}
+
+#[naked]
+extern "C" fn private_naked() -> u32 {
+    unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
+}
+
+#[no_mangle]
+pub extern "C" fn public_vanilla() -> u32 {
+    42
+}
+
+#[naked]
+#[no_mangle]
+pub extern "C" fn public_naked() -> u32 {
+    unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
+}
+
+pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
+    T::COUNT
+}
+
+#[naked]
+pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 {
+    unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) }
+}
+
+#[linkage = "external"]
+extern "C" fn vanilla_external_linkage() -> u32 {
+    42
+}
+
+#[naked]
+#[linkage = "external"]
+extern "C" fn naked_external_linkage() -> u32 {
+    unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
+}
+
+#[cfg(not(windows))]
+#[linkage = "weak"]
+extern "C" fn vanilla_weak_linkage() -> u32 {
+    42
+}
+
+#[naked]
+#[cfg(not(windows))]
+#[linkage = "weak"]
+extern "C" fn naked_weak_linkage() -> u32 {
+    unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
+}
+
+// functions that are declared in an `extern "C"` block are currently not exported
+// this maybe should change in the future, this is just tracking the current behavior
+// reported in https://github.com/rust-lang/rust/issues/128071
+std::arch::global_asm! {
+    ".globl function_defined_in_global_asm",
+    "function_defined_in_global_asm:",
+    "ret",
+}
+
+extern "C" {
+    pub fn function_defined_in_global_asm();
+}
diff --git a/tests/run-make/naked-symbol-visibility/rmake.rs b/tests/run-make/naked-symbol-visibility/rmake.rs
new file mode 100644
index 00000000000..a32e62326eb
--- /dev/null
+++ b/tests/run-make/naked-symbol-visibility/rmake.rs
@@ -0,0 +1,98 @@
+//@ ignore-windows
+//@ only-x86_64
+use run_make_support::object::read::{File, Object, Symbol};
+use run_make_support::object::ObjectSymbol;
+use run_make_support::targets::is_windows;
+use run_make_support::{dynamic_lib_name, env_var, rfs, rustc};
+
+fn main() {
+    let rdylib_name = dynamic_lib_name("a_rust_dylib");
+    rustc().arg("-Zshare-generics=no").input("a_rust_dylib.rs").run();
+
+    let binary_data = rfs::read(&rdylib_name);
+    let rdylib = File::parse(&*binary_data).unwrap();
+
+    // naked should mirror vanilla
+    not_exported(&rdylib, "private_vanilla");
+    not_exported(&rdylib, "private_naked");
+
+    global_function(&rdylib, "public_vanilla");
+    global_function(&rdylib, "public_naked");
+
+    not_exported(&rdylib, "public_vanilla_generic");
+    not_exported(&rdylib, "public_naked_generic");
+
+    global_function(&rdylib, "vanilla_external_linkage");
+    global_function(&rdylib, "naked_external_linkage");
+
+    // FIXME: make this work on windows (gnu and msvc). See the PR
+    // https://github.com/rust-lang/rust/pull/128362 for some approaches
+    // that don't work
+    //
+    // #[linkage = "weak"] does not work well on windows, we get
+    //
+    // lib.def : error LNK2001: unresolved external symbol naked_weak_linkage␍
+    // lib.def : error LNK2001: unresolved external symbol vanilla_weak_linkage
+    //
+    // so just skip weak symbols on windows (for now)
+    if !is_windows() {
+        weak_function(&rdylib, "vanilla_weak_linkage");
+        weak_function(&rdylib, "naked_weak_linkage");
+    }
+
+    // functions that are declared in an `extern "C"` block are currently not exported
+    // this maybe should change in the future, this is just tracking the current behavior
+    // reported in https://github.com/rust-lang/rust/issues/128071
+    not_exported(&rdylib, "function_defined_in_global_asm");
+
+    // share generics should expose the generic functions
+    rustc().arg("-Zshare-generics=yes").input("a_rust_dylib.rs").run();
+    let binary_data = rfs::read(&rdylib_name);
+    let rdylib = File::parse(&*binary_data).unwrap();
+
+    global_function(&rdylib, "public_vanilla_generic");
+    global_function(&rdylib, "public_naked_generic");
+}
+
+#[track_caller]
+fn global_function(file: &File, symbol_name: &str) {
+    let symbols = find_dynamic_symbol(file, symbol_name);
+    let [symbol] = symbols.as_slice() else {
+        panic!("symbol {symbol_name} occurs {} times", symbols.len())
+    };
+
+    assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
+    assert!(symbol.is_global(), "`{symbol_name}` is not marked as global");
+}
+
+#[track_caller]
+fn weak_function(file: &File, symbol_name: &str) {
+    let symbols = find_dynamic_symbol(file, symbol_name);
+    let [symbol] = symbols.as_slice() else {
+        panic!("symbol {symbol_name} occurs {} times", symbols.len())
+    };
+
+    assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
+    assert!(symbol.is_weak(), "`{symbol_name}` is not marked as weak");
+}
+
+#[track_caller]
+fn not_exported(file: &File, symbol_name: &str) {
+    assert_eq!(find_dynamic_symbol(file, symbol_name).len(), 0)
+}
+
+fn find_subsequence(haystack: &[u8], needle: &[u8]) -> bool {
+    haystack.windows(needle.len()).any(|window| window == needle)
+}
+
+fn find_dynamic_symbol<'file, 'data>(
+    file: &'file File<'data>,
+    expected: &str,
+) -> Vec<Symbol<'data, 'file>> {
+    file.exports()
+        .unwrap()
+        .into_iter()
+        .filter(|e| find_subsequence(e.name(), expected.as_bytes()))
+        .filter_map(|e| file.symbol_by_name_bytes(e.name()))
+        .collect()
+}
diff --git a/tests/run-make/no-duplicate-libs/main.rs b/tests/run-make/no-duplicate-libs/main.rs
index b25ef35ada6..d8d5d58bc47 100644
--- a/tests/run-make/no-duplicate-libs/main.rs
+++ b/tests/run-make/no-duplicate-libs/main.rs
@@ -1,6 +1,6 @@
-#[link(name = "foo")] // linker should drop this library, no symbols used
-#[link(name = "bar")] // symbol comes from this library
-#[link(name = "foo")] // now linker picks up `foo` b/c `bar` library needs it
+#[link(name = "foo", kind = "static")] // linker should drop this library, no symbols used
+#[link(name = "bar", kind = "static")] // symbol comes from this library
+#[link(name = "foo", kind = "static")] // now linker picks up `foo` b/c `bar` library needs it
 extern "C" {
     fn bar();
 }
diff --git a/tests/run-make/no-duplicate-libs/rmake.rs b/tests/run-make/no-duplicate-libs/rmake.rs
index 469348e266c..b67067909b2 100644
--- a/tests/run-make/no-duplicate-libs/rmake.rs
+++ b/tests/run-make/no-duplicate-libs/rmake.rs
@@ -9,9 +9,6 @@
 //@ ignore-cross-compile
 // Reason: the compiled binary is executed
 
-//@ ignore-msvc
-// Reason: native compilation results in an unresolved external symbol
-
 use run_make_support::{build_native_static_lib, run, rustc};
 
 fn main() {
diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/Makefile b/tests/run-make/pdb-buildinfo-cl-cmd/Makefile
deleted file mode 100644
index a7be301a5b0..00000000000
--- a/tests/run-make/pdb-buildinfo-cl-cmd/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-include ../tools.mk
-
-# only-windows-msvc
-
-# tests if the pdb contains the following information in the LF_BUILDINFO:
-# 1. the commandline args to compile it (cmd)
-# 2. full path to the compiler (cl)
-
-# we just do a stringsearch on the pdb, as these need to show up at least once, as the LF_BUILDINFO is created for each cgu
-# actual parsing would be better, but this is a simple and good enough solution for now
-
-all:
-	$(RUSTC_ORIGINAL) main.rs -g --crate-name my_crate_name --crate-type bin -C metadata=dc9ef878b0a48666 --out-dir $(TMPDIR)
-	cat '$(TMPDIR)/my_crate_name.pdb' | grep -F '$(RUSTC_ORIGINAL)'
-# using a file containing the string so I don't have problems with escaping quotes and spaces 
-	cat '$(TMPDIR)/my_crate_name.pdb' | grep -f 'stringlist.txt'
diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/rmake.rs b/tests/run-make/pdb-buildinfo-cl-cmd/rmake.rs
new file mode 100644
index 00000000000..2ab9057b24c
--- /dev/null
+++ b/tests/run-make/pdb-buildinfo-cl-cmd/rmake.rs
@@ -0,0 +1,39 @@
+// Check if the pdb file contains the following information in the LF_BUILDINFO:
+// 1. full path to the compiler (cl)
+// 2. the commandline args to compile it (cmd)
+// This is because these used to be missing in #96475.
+// See https://github.com/rust-lang/rust/pull/113492
+
+//@ only-windows-msvc
+// Reason: pdb files are unique to this architecture
+
+use run_make_support::{assert_contains, bstr, env_var, rfs, rustc};
+
+fn main() {
+    rustc()
+        .input("main.rs")
+        .arg("-g")
+        .crate_name("my_crate_name")
+        .crate_type("bin")
+        .metadata("dc9ef878b0a48666")
+        .run();
+    let tests = [
+        &env_var("RUSTC"),
+        r#""main.rs""#,
+        r#""-g""#,
+        r#""--crate-name""#,
+        r#""my_crate_name""#,
+        r#""--crate-type""#,
+        r#""bin""#,
+        r#""-Cmetadata=dc9ef878b0a48666""#,
+    ];
+    for test in tests {
+        assert_pdb_contains(test);
+    }
+}
+
+fn assert_pdb_contains(needle: &str) {
+    let needle = needle.as_bytes();
+    use bstr::ByteSlice;
+    assert!(&rfs::read("my_crate_name.pdb").find(needle).is_some());
+}
diff --git a/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt b/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt
deleted file mode 100644
index 634e9f19e89..00000000000
--- a/tests/run-make/pdb-buildinfo-cl-cmd/stringlist.txt
+++ /dev/null
@@ -1 +0,0 @@
-"main.rs" "-g" "--crate-name" "my_crate_name" "--crate-type" "bin" "-C" "metadata=dc9ef878b0a48666" "--out-dir"
\ No newline at end of file
diff --git a/tests/run-make/pgo-gen-lto/Makefile b/tests/run-make/pgo-gen-lto/Makefile
deleted file mode 100644
index 54164c99522..00000000000
--- a/tests/run-make/pgo-gen-lto/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# needs-profiler-support
-# ignore-cross-compile
-
-include ../tools.mk
-
-COMPILE_FLAGS=-Copt-level=3 -Clto=fat -Cprofile-generate="$(TMPDIR)"
-
-all:
-	$(RUSTC) $(COMPILE_FLAGS) test.rs
-	$(call RUN,test) || exit 1
-	[ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1)
diff --git a/tests/run-make/pgo-gen-lto/rmake.rs b/tests/run-make/pgo-gen-lto/rmake.rs
new file mode 100644
index 00000000000..53d1623bf58
--- /dev/null
+++ b/tests/run-make/pgo-gen-lto/rmake.rs
@@ -0,0 +1,22 @@
+// A simple smoke test: when rustc compiles with profiling enabled, a profraw file
+// should be generated.
+// See https://github.com/rust-lang/rust/pull/48346
+
+//@ needs-profiler-support
+// Reason: this exercises LTO profiling
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{cwd, has_extension, has_prefix, run, rustc, shallow_find_files};
+
+fn main() {
+    rustc().opt_level("3").arg("-Clto=fat").profile_generate(cwd()).input("test.rs").run();
+    run("test");
+    assert_eq!(
+        shallow_find_files(cwd(), |path| {
+            has_prefix(path, "default_") && has_extension(path, "profraw")
+        })
+        .len(),
+        1
+    );
+}
diff --git a/tests/run-make/pgo-indirect-call-promotion/Makefile b/tests/run-make/pgo-indirect-call-promotion/Makefile
deleted file mode 100644
index 8d1e69c4aba..00000000000
--- a/tests/run-make/pgo-indirect-call-promotion/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-# needs-profiler-support
-# ignore-cross-compile
-
-include ../tools.mk
-
-all:
-	# We don't compile `opaque` with either optimizations or instrumentation.
-	# We don't compile `opaque` with either optimizations or instrumentation.
-	$(RUSTC) $(COMMON_FLAGS) opaque.rs
-	# Compile the test program with instrumentation
-	mkdir -p "$(TMPDIR)"/prof_data_dir
-	$(RUSTC) $(COMMON_FLAGS) interesting.rs \
-		-Cprofile-generate="$(TMPDIR)"/prof_data_dir -O -Ccodegen-units=1
-	$(RUSTC) $(COMMON_FLAGS) main.rs -Cprofile-generate="$(TMPDIR)"/prof_data_dir -O
-	# The argument below generates to the expected branch weights
-	$(call RUN,main) || exit 1
-	"$(LLVM_BIN_DIR)"/llvm-profdata merge \
-		-o "$(TMPDIR)"/prof_data_dir/merged.profdata \
-		"$(TMPDIR)"/prof_data_dir
-	$(RUSTC) $(COMMON_FLAGS) interesting.rs \
-		-Cprofile-use="$(TMPDIR)"/prof_data_dir/merged.profdata -O \
-		-Ccodegen-units=1 --emit=llvm-ir
-	cat "$(TMPDIR)"/interesting.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt
diff --git a/tests/run-make/pgo-indirect-call-promotion/rmake.rs b/tests/run-make/pgo-indirect-call-promotion/rmake.rs
new file mode 100644
index 00000000000..d0ccfd8a4d7
--- /dev/null
+++ b/tests/run-make/pgo-indirect-call-promotion/rmake.rs
@@ -0,0 +1,33 @@
+// This test checks that indirect call promotion is performed. The test
+// programs calls the same function a thousand times through a function pointer.
+// Only PGO data provides the information that it actually always is the same
+// function. We verify that the indirect call promotion pass inserts a check
+// whether it can make a direct call instead of the indirect call.
+// See https://github.com/rust-lang/rust/pull/66631
+
+//@ needs-profiler-support
+// Reason: llvm_profdata is used
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{llvm_filecheck, llvm_profdata, rfs, run, rustc};
+
+fn main() {
+    // We don't compile `opaque` with either optimizations or instrumentation.
+    rustc().input("opaque.rs").run();
+    // Compile the test program with instrumentation
+    rfs::create_dir("prof_data_dir");
+    rustc().input("interesting.rs").profile_generate("prof_data_dir").opt().codegen_units(1).run();
+    rustc().input("main.rs").profile_generate("prof_data_dir").opt().run();
+    // The argument below generates to the expected branch weights
+    run("main");
+    llvm_profdata().merge().output("prof_data_dir/merged.profdata").input("prof_data_dir").run();
+    rustc()
+        .input("interesting.rs")
+        .profile_use("prof_data_dir/merged.profdata")
+        .opt()
+        .codegen_units(1)
+        .emit("llvm-ir")
+        .run();
+    llvm_filecheck().patterns("filecheck-patterns.txt").stdin(rfs::read("interesting.ll")).run();
+}
diff --git a/tests/run-make/print-calling-conventions/Makefile b/tests/run-make/print-calling-conventions/Makefile
deleted file mode 100644
index 27b87e61086..00000000000
--- a/tests/run-make/print-calling-conventions/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) --print calling-conventions
diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs
index d83e8a36f2c..471a99b90d9 100644
--- a/tests/run-make/print-cfg/rmake.rs
+++ b/tests/run-make/print-cfg/rmake.rs
@@ -6,7 +6,6 @@
 //! It also checks that some targets have the correct set cfgs.
 
 use std::collections::HashSet;
-use std::ffi::OsString;
 use std::iter::FromIterator;
 use std::path::PathBuf;
 
@@ -91,10 +90,8 @@ fn check(PrintCfg { target, includes, disallow }: PrintCfg) {
     // --print=cfg=PATH
     {
         let tmp_path = PathBuf::from(format!("{target}.cfg"));
-        let mut print_arg = OsString::from("--print=cfg=");
-        print_arg.push(tmp_path.as_os_str());
 
-        rustc().target(target).arg(print_arg).run();
+        rustc().target(target).print(&format!("cfg={}", tmp_path.display())).run();
 
         let output = rfs::read_to_string(&tmp_path);
 
diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs
index 4a79910c8e0..b10336f88c6 100644
--- a/tests/run-make/print-check-cfg/rmake.rs
+++ b/tests/run-make/print-check-cfg/rmake.rs
@@ -87,7 +87,7 @@ fn main() {
 
 fn check(CheckCfg { args, contains }: CheckCfg) {
     let output =
-        rustc().input("lib.rs").arg("-Zunstable-options").arg("--print=check-cfg").args(args).run();
+        rustc().input("lib.rs").arg("-Zunstable-options").print("check-cfg").args(args).run();
 
     let stdout = output.stdout_utf8();
 
diff --git a/tests/run-make/print-target-list/Makefile b/tests/run-make/print-target-list/Makefile
deleted file mode 100644
index f23c40d4281..00000000000
--- a/tests/run-make/print-target-list/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-include ../tools.mk
-
-# Checks that all the targets returned by `rustc --print target-list` are valid
-# target specifications
-all:
-	for target in $(shell $(BARE_RUSTC) --print target-list); do \
-		$(BARE_RUSTC) --target $$target --print sysroot; \
-	done
diff --git a/tests/run-make/print-target-list/rmake.rs b/tests/run-make/print-target-list/rmake.rs
new file mode 100644
index 00000000000..743ed52069d
--- /dev/null
+++ b/tests/run-make/print-target-list/rmake.rs
@@ -0,0 +1,21 @@
+// Checks that all the targets returned by `rustc --print target-list` are valid
+// target specifications
+
+use run_make_support::bare_rustc;
+
+// FIXME(127877): certain experimental targets fail with creating a 'LLVM TargetMachine'
+// in CI, so we skip them
+const EXPERIMENTAL_TARGETS: &[&str] = &["avr", "m68k", "csky", "xtensa"];
+
+fn main() {
+    let targets = bare_rustc().print("target-list").run().stdout_utf8();
+
+    for target in targets.lines() {
+        // skip experimental targets that would otherwise fail
+        if EXPERIMENTAL_TARGETS.iter().any(|experimental| target.contains(experimental)) {
+            continue;
+        }
+
+        bare_rustc().target(target).print("sysroot").run();
+    }
+}
diff --git a/tests/run-make/print-to-output/rmake.rs b/tests/run-make/print-to-output/rmake.rs
index d0cba725b36..db2a291f8e7 100644
--- a/tests/run-make/print-to-output/rmake.rs
+++ b/tests/run-make/print-to-output/rmake.rs
@@ -1,7 +1,6 @@
 //! This checks the output of some `--print` options when
 //! output to a file (instead of stdout)
 
-use std::ffi::OsString;
 use std::path::PathBuf;
 
 use run_make_support::{rfs, rustc, target};
@@ -44,10 +43,8 @@ fn check(args: Option) {
     // --print={option}=PATH
     let output = {
         let tmp_path = PathBuf::from(format!("{}.txt", args.option));
-        let mut print_arg = OsString::from(format!("--print={}=", args.option));
-        print_arg.push(tmp_path.as_os_str());
 
-        rustc().target(args.target).arg(print_arg).run();
+        rustc().target(args.target).print(&format!("{}={}", args.option, tmp_path.display())).run();
 
         rfs::read_to_string(&tmp_path)
     };
diff --git a/tests/run-make/raw-dylib-alt-calling-convention/Makefile b/tests/run-make/raw-dylib-alt-calling-convention/Makefile
deleted file mode 100644
index 14d23a5d201..00000000000
--- a/tests/run-make/raw-dylib-alt-calling-convention/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-# Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions.
-
-# only-x86
-# only-windows
-
-include ../tools.mk
-
-all:
-	$(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
-	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
-	$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
-ifdef IS_MSVC
-	$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
-else
-	$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
-endif
-
-	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
-	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt
-
-ifdef IS_MSVC
-	"$(TMPDIR)"/driver true > "$(TMPDIR)"/output.msvc.txt
-	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.msvc.txt output.msvc.txt
-endif
diff --git a/tests/run-make/raw-dylib-alt-calling-convention/rmake.rs b/tests/run-make/raw-dylib-alt-calling-convention/rmake.rs
new file mode 100644
index 00000000000..1a1622f2754
--- /dev/null
+++ b/tests/run-make/raw-dylib-alt-calling-convention/rmake.rs
@@ -0,0 +1,32 @@
+// `raw-dylib` is a Windows-specific attribute which emits idata sections for the items in the
+// attached extern block,
+// so they may be linked against without linking against an import library.
+// To learn more, read https://github.com/rust-lang/rfcs/blob/master/text/2627-raw-dylib-kind.md
+// This test uses this feature alongside alternative calling conventions, checking that both
+// features are compatible and result in the expected output upon execution of the binary.
+// See https://github.com/rust-lang/rust/pull/84171
+
+//@ only-x86
+//@ only-windows
+
+use run_make_support::{build_native_dynamic_lib, diff, is_msvc, run, run_with_args, rustc};
+
+fn main() {
+    rustc()
+        .crate_type("lib")
+        .crate_name("raw_dylib_alt_calling_convention_test")
+        .input("lib.rs")
+        .run();
+    rustc().crate_type("bin").input("driver.rs").run();
+    build_native_dynamic_lib("extern");
+    let out = run("driver").stdout_utf8();
+    diff().expected_file("output.txt").actual_text("actual", out).normalize(r#"\r"#, "").run();
+    if is_msvc() {
+        let out_msvc = run_with_args("driver", &["true"]).stdout_utf8();
+        diff()
+            .expected_file("output.msvc.txt")
+            .actual_text("actual", out_msvc)
+            .normalize(r#"\r"#, "")
+            .run();
+    }
+}
diff --git a/tests/run-make/raw-dylib-c/Makefile b/tests/run-make/raw-dylib-c/Makefile
deleted file mode 100644
index af5c4a6edd7..00000000000
--- a/tests/run-make/raw-dylib-c/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
-
-# only-windows
-
-include ../tools.mk
-
-all:
-	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
-	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
-	$(RUSTC) --crate-type bin --crate-name raw_dylib_test_bin lib.rs
-	$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
-	$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
-ifdef IS_MSVC
-	$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
-	$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
-else
-	$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
-	$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
-endif
-	"$(TMPDIR)"/driver | tr -d '\r' > "$(TMPDIR)"/output.txt
-	"$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/output.txt output.txt
-else
-	$(DIFF) output.txt "$(TMPDIR)"/output.txt
-	$(DIFF) output.txt "$(TMPDIR)"/output_bin.txt
-endif
diff --git a/tests/run-make/raw-dylib-c/rmake.rs b/tests/run-make/raw-dylib-c/rmake.rs
new file mode 100644
index 00000000000..3cfd8cb400b
--- /dev/null
+++ b/tests/run-make/raw-dylib-c/rmake.rs
@@ -0,0 +1,29 @@
+// `raw-dylib` is a Windows-specific attribute which emits idata sections for the items in the
+// attached extern block,
+// so they may be linked against without linking against an import library.
+// To learn more, read https://github.com/rust-lang/rfcs/blob/master/text/2627-raw-dylib-kind.md
+// This test is the simplest of the raw-dylib tests, simply smoke-testing that the feature
+// can be used to build an executable binary with an expected output with native C files
+// compiling into dynamic libraries.
+// See https://github.com/rust-lang/rust/pull/86419
+
+//@ only-windows
+
+use run_make_support::{build_native_dynamic_lib, diff, run, rustc};
+
+fn main() {
+    rustc().crate_type("lib").crate_name("raw_dylib_test").input("lib.rs").run();
+    rustc().crate_type("bin").input("driver.rs").run();
+    rustc().crate_type("bin").crate_name("raw_dylib_test_bin").input("lib.rs").run();
+    build_native_dynamic_lib("extern_1");
+    build_native_dynamic_lib("extern_2");
+    let out_driver = run("driver").stdout_utf8();
+    let out_raw = run("raw_dylib_test_bin").stdout_utf8();
+
+    diff()
+        .expected_file("output.txt")
+        .actual_text("actual", out_driver)
+        .normalize(r#"\r"#, "")
+        .run();
+    diff().expected_file("output.txt").actual_text("actual", out_raw).normalize(r#"\r"#, "").run();
+}
diff --git a/tests/run-make/redundant-libs/Makefile b/tests/run-make/redundant-libs/Makefile
deleted file mode 100644
index 0a48b2b2801..00000000000
--- a/tests/run-make/redundant-libs/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# ignore-windows-msvc
-
-# rustc will remove one of the two redundant references to foo below.  Depending
-# on which one gets removed, we'll get a linker error on SOME platforms (like
-# Linux).  On these platforms, when a library is referenced, the linker will
-# only pull in the symbols needed _at that point in time_.  If a later library
-# depends on additional symbols from the library, they will not have been pulled
-# in, and you'll get undefined symbols errors.
-#
-# So in this example, we need to ensure that rustc keeps the _later_ reference
-# to foo, and not the former one.
-RUSTC_FLAGS = \
-    -l static=bar \
-    -l foo \
-    -l static=baz \
-    -l foo \
-    --print link-args
-
-all: $(call DYLIB,foo) $(call STATICLIB,bar) $(call STATICLIB,baz)
-	$(RUSTC) $(RUSTC_FLAGS) main.rs
-	$(call RUN,main)
diff --git a/tests/run-make/redundant-libs/foo.c b/tests/run-make/redundant-libs/foo.c
index 339ee86c99e..551b85d1824 100644
--- a/tests/run-make/redundant-libs/foo.c
+++ b/tests/run-make/redundant-libs/foo.c
@@ -1,2 +1,8 @@
-void foo1() {}
-void foo2() {}
+#ifdef _MSC_VER
+#define DllExport __declspec(dllexport)
+#else
+#define DllExport
+#endif
+
+DllExport void foo1() {}
+DllExport void foo2() {}
diff --git a/tests/run-make/redundant-libs/rmake.rs b/tests/run-make/redundant-libs/rmake.rs
new file mode 100644
index 00000000000..43bb30bde70
--- /dev/null
+++ b/tests/run-make/redundant-libs/rmake.rs
@@ -0,0 +1,28 @@
+// rustc will remove one of the two redundant references to foo below.  Depending
+// on which one gets removed, we'll get a linker error on SOME platforms (like
+// Linux).  On these platforms, when a library is referenced, the linker will
+// only pull in the symbols needed _at that point in time_.  If a later library
+// depends on additional symbols from the library, they will not have been pulled
+// in, and you'll get undefined symbols errors.
+//
+// So in this example, we need to ensure that rustc keeps the _later_ reference
+// to foo, and not the former one.
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{
+    build_native_dynamic_lib, build_native_static_lib, cwd, is_msvc, rfs, run, rustc,
+};
+
+fn main() {
+    build_native_dynamic_lib("foo");
+    build_native_static_lib("bar");
+    build_native_static_lib("baz");
+    rustc()
+        .args(&["-lstatic=bar", "-lfoo", "-lstatic=baz", "-lfoo"])
+        .input("main.rs")
+        .print("link-args")
+        .run();
+    run("main");
+}
diff --git a/tests/run-make/reproducible-build-2/Makefile b/tests/run-make/reproducible-build-2/Makefile
deleted file mode 100644
index 68fcac8b47f..00000000000
--- a/tests/run-make/reproducible-build-2/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# ignore-musl
-# ignore-windows
-# Objects are reproducible but their path is not.
-
-all:  \
-	fat_lto \
-	sysroot
-
-fat_lto:
-	rm -rf $(TMPDIR) && mkdir $(TMPDIR)
-	$(RUSTC) reproducible-build-aux.rs
-	$(RUSTC) reproducible-build.rs -C lto=fat
-	cp $(TMPDIR)/reproducible-build $(TMPDIR)/reproducible-build-a
-	$(RUSTC) reproducible-build.rs -C lto=fat
-	cmp "$(TMPDIR)/reproducible-build-a" "$(TMPDIR)/reproducible-build" || exit 1
-
-sysroot:
-	rm -rf $(TMPDIR) && mkdir $(TMPDIR)
-	$(RUSTC) reproducible-build-aux.rs
-	$(RUSTC) reproducible-build.rs --crate-type rlib --sysroot $(shell $(RUSTC) --print sysroot) --remap-path-prefix=$(shell $(RUSTC) --print sysroot)=/sysroot
-	cp -R $(shell $(RUSTC) --print sysroot) $(TMPDIR)/sysroot
-	cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfoo.rlib
-	$(RUSTC) reproducible-build.rs --crate-type rlib --sysroot $(TMPDIR)/sysroot --remap-path-prefix=$(TMPDIR)/sysroot=/sysroot
-	cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1
diff --git a/tests/run-make/reproducible-build-2/rmake.rs b/tests/run-make/reproducible-build-2/rmake.rs
new file mode 100644
index 00000000000..c500c4238b0
--- /dev/null
+++ b/tests/run-make/reproducible-build-2/rmake.rs
@@ -0,0 +1,47 @@
+// Builds with fat link-time-optimizations and the --sysroot flag used to be
+// non-deterministic - that means, compiling twice with no changes would create
+// slightly different outputs. This has been fixed by #63352 and #63505.
+// Test 1: Compile with fat-lto twice, check that both compilation outputs are identical.
+// Test 2: Compile with sysroot, then change the sysroot path from absolute to relative.
+// Outputs should be identical.
+// See https://github.com/rust-lang/rust/issues/34902
+
+//@ ignore-windows
+// Reasons:
+// 1. The object files are reproducible, but their paths are not, which causes
+// the first assertion in the test to fail.
+// 2. When the sysroot gets copied, some symlinks must be re-created,
+// which is a privileged action on Windows.
+
+use run_make_support::{bin_name, rfs, rust_lib_name, rustc};
+
+fn main() {
+    // test 1: fat lto
+    rustc().input("reproducible-build-aux.rs").run();
+    rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
+    rfs::rename("reproducible-build", "reproducible-build-a");
+    rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
+    assert_eq!(rfs::read("reproducible-build"), rfs::read("reproducible-build-a"));
+
+    // test 2: sysroot
+    let sysroot = rustc().print("sysroot").run().stdout_utf8();
+    let sysroot = sysroot.trim();
+
+    rustc().input("reproducible-build-aux.rs").run();
+    rustc()
+        .input("reproducible-build.rs")
+        .crate_type("rlib")
+        .sysroot(&sysroot)
+        .arg(format!("--remap-path-prefix={sysroot}=/sysroot"))
+        .run();
+    rfs::copy_dir_all(&sysroot, "sysroot");
+    rfs::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo"));
+    rustc()
+        .input("reproducible-build.rs")
+        .crate_type("rlib")
+        .sysroot("sysroot")
+        .arg("--remap-path-prefix=/sysroot=/sysroot")
+        .run();
+
+    assert_eq!(rfs::read(rust_lib_name("reproducible_build")), rfs::read(rust_lib_name("foo")));
+}
diff --git a/tests/run-make/rust-lld-compress-debug-sections/main.rs b/tests/run-make/rust-lld-compress-debug-sections/main.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make/rust-lld-compress-debug-sections/main.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/rust-lld-compress-debug-sections/rmake.rs b/tests/run-make/rust-lld-compress-debug-sections/rmake.rs
new file mode 100644
index 00000000000..df9691ccbcf
--- /dev/null
+++ b/tests/run-make/rust-lld-compress-debug-sections/rmake.rs
@@ -0,0 +1,39 @@
+// Checks the `compress-debug-sections` option on rust-lld.
+
+//@ needs-rust-lld
+//@ only-linux
+//@ ignore-cross-compile
+
+// FIXME: This test isn't comprehensive and isn't covering all possible combinations.
+
+use run_make_support::{assert_contains, cmd, llvm_readobj, run_in_tmpdir, rustc};
+
+fn check_compression(compression: &str, to_find: &str) {
+    run_in_tmpdir(|| {
+        let out = rustc()
+            .arg("-Zlinker-features=+lld")
+            .arg("-Clink-self-contained=+linker")
+            .arg("-Zunstable-options")
+            .arg("-Cdebuginfo=full")
+            .link_arg(&format!("-Wl,--compress-debug-sections={compression}"))
+            .input("main.rs")
+            .run_unchecked();
+        let stderr = out.stderr_utf8();
+        if stderr.is_empty() {
+            llvm_readobj().arg("-t").arg("main").run().assert_stdout_contains(to_find);
+        } else {
+            assert_contains(
+                stderr,
+                format!(
+                    "LLVM was not built with LLVM_ENABLE_{to_find} \
+                     or did not find {compression} at build time"
+                ),
+            );
+        }
+    });
+}
+
+fn main() {
+    check_compression("zlib", "ZLIB");
+    check_compression("zstd", "ZSTD");
+}
diff --git a/tests/run-make/rust-lld/rmake.rs b/tests/run-make/rust-lld/rmake.rs
index 87477c12230..d0bc19130d7 100644
--- a/tests/run-make/rust-lld/rmake.rs
+++ b/tests/run-make/rust-lld/rmake.rs
@@ -2,15 +2,17 @@
 // see https://github.com/rust-lang/compiler-team/issues/510 for more info
 
 //@ needs-rust-lld
-//@ ignore-msvc
 //@ ignore-s390x lld does not yet support s390x as target
 
 use std::process::Output;
 
 use run_make_support::regex::Regex;
-use run_make_support::rustc;
+use run_make_support::{is_msvc, rustc};
 
 fn main() {
+    // lld-link is used if msvc, otherwise a gnu-compatible lld is used.
+    let linker_version_flag = if is_msvc() { "--version" } else { "-Wl,-v" };
+
     // Opt-in to lld and the self-contained linker, to link with rust-lld. We'll check that by
     // asking the linker to display its version number with a link-arg.
     let output = rustc()
@@ -18,7 +20,7 @@ fn main() {
         .arg("-Zlinker-features=+lld")
         .arg("-Clink-self-contained=+linker")
         .arg("-Zunstable-options")
-        .link_arg("-Wl,-v")
+        .link_arg(linker_version_flag)
         .input("main.rs")
         .run();
     assert!(
@@ -27,10 +29,10 @@ fn main() {
         output.stderr_utf8()
     );
 
-    // It should not be used when we explictly opt-out of lld.
+    // It should not be used when we explicitly opt-out of lld.
     let output = rustc()
         .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
-        .link_arg("-Wl,-v")
+        .link_arg(linker_version_flag)
         .arg("-Zlinker-features=-lld")
         .input("main.rs")
         .run();
@@ -44,7 +46,7 @@ fn main() {
     // times to rustc.
     let output = rustc()
         .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
-        .link_arg("-Wl,-v")
+        .link_arg(linker_version_flag)
         .arg("-Clink-self-contained=+linker")
         .arg("-Zunstable-options")
         .arg("-Zlinker-features=-lld")
diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout
index bc38d9e9dc6..bc38d9e9dc6 100644
--- a/tests/run-make/issue-88756-default-output/output-default.stdout
+++ b/tests/run-make/rustdoc-default-output/output-default.stdout
diff --git a/tests/run-make/rustdoc-default-output/rmake.rs b/tests/run-make/rustdoc-default-output/rmake.rs
new file mode 100644
index 00000000000..06720445a35
--- /dev/null
+++ b/tests/run-make/rustdoc-default-output/rmake.rs
@@ -0,0 +1,16 @@
+// Calling rustdoc with no arguments, which should bring up a help menu, used to
+// cause an error as rustdoc expects an input file. Fixed in #98331, this test
+// ensures the output of rustdoc's help menu is as expected.
+// See https://github.com/rust-lang/rust/issues/88756
+
+use run_make_support::{bare_rustdoc, diff};
+
+fn main() {
+    let out = bare_rustdoc().run().stdout_utf8();
+    diff()
+        .expected_file("output-default.stdout")
+        .actual_text("actual", out)
+        // replace the channel type in the URL with $CHANNEL
+        .normalize(r"nightly/|beta/|stable/|1\.[0-9]+\.[0-9]+/", "$$CHANNEL/")
+        .run();
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
index bfe4a1df456..b77df7adc8d 100644
--- a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
@@ -11,8 +11,7 @@ fn main() {
     let dylib_name = rustc()
         .crate_name(proc_crate_name)
         .crate_type("dylib")
-        .arg("--print")
-        .arg("file-names")
+        .print("file-names")
         .arg("-")
         .run()
         .stdout_utf8();
diff --git a/tests/run-make/simd-ffi/Makefile b/tests/run-make/simd-ffi/Makefile
deleted file mode 100644
index 29735347041..00000000000
--- a/tests/run-make/simd-ffi/Makefile
+++ /dev/null
@@ -1,47 +0,0 @@
-include ../tools.mk
-
-TARGETS =
-ifeq ($(filter arm,$(LLVM_COMPONENTS)),arm)
-# construct a fairly exhaustive list of platforms that we
-# support. These ones don't follow a pattern
-TARGETS += arm-linux-androideabi arm-unknown-linux-gnueabihf arm-unknown-linux-gnueabi
-endif
-
-ifeq ($(filter x86,$(LLVM_COMPONENTS)),x86)
-X86_ARCHS = i686 x86_64
-else
-X86_ARCHS =
-endif
-
-# these ones do, each OS lists the architectures it supports
-LINUX=$(filter aarch64 mips,$(LLVM_COMPONENTS)) $(X86_ARCHS)
-ifeq ($(filter mips,$(LLVM_COMPONENTS)),mips)
-LINUX += mipsel
-endif
-
-WINDOWS=$(X86_ARCHS)
-# fails with: failed to get iphonesimulator SDK path: no such file or directory
-#IOS=i386 aarch64 armv7
-DARWIN=$(X86_ARCHS)
-
-$(foreach arch,$(LINUX),$(eval TARGETS += $(arch)-unknown-linux-gnu))
-$(foreach arch,$(WINDOWS),$(eval TARGETS += $(arch)-pc-windows-gnu))
-#$(foreach arch,$(IOS),$(eval TARGETS += $(arch)-apple-ios))
-$(foreach arch,$(DARWIN),$(eval TARGETS += $(arch)-apple-darwin))
-
-all: $(TARGETS)
-
-define MK_TARGETS
-# compile the rust file to the given target, but only to asm and IR
-# form, to avoid having to have an appropriate linker.
-#
-# we need some features because the integer SIMD instructions are not
-# enabled by-default for i686 and ARM; these features will be invalid
-# on some platforms, but LLVM just prints a warning so that's fine for
-# now.
-$(1): simd.rs
-	$$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs \
-                -C target-feature='+neon,+sse2' -C extra-filename=-$(1)
-endef
-
-$(foreach targetxxx,$(TARGETS),$(eval $(call MK_TARGETS,$(targetxxx))))
diff --git a/tests/run-make/simd-ffi/rmake.rs b/tests/run-make/simd-ffi/rmake.rs
new file mode 100644
index 00000000000..04990c8bdf4
--- /dev/null
+++ b/tests/run-make/simd-ffi/rmake.rs
@@ -0,0 +1,63 @@
+// Using SIMD types in a program with foreign-function interfaces used to result in an ICE
+// (internal compiler error). Since this was fixed in #21233, it should be checked that
+// compilation of SIMD and FFI together should be successful on all the most common
+// architectures.
+// Note that this test does not check linking or binary execution.
+// See https://github.com/rust-lang/rust/pull/21233
+
+use run_make_support::{llvm_components_contain, rustc};
+
+fn main() {
+    let mut targets = Vec::new();
+    // arm-specific targets.
+    if llvm_components_contain("arm") {
+        targets.append(&mut vec![
+            "arm-linux-androideabi".to_owned(),
+            "arm-unknown-linux-gnueabihf".to_owned(),
+            "arm-unknown-linux-gnueabi".to_owned(),
+        ]);
+    }
+    let mut x86_archs = Vec::new();
+    if llvm_components_contain("x86") {
+        x86_archs.append(&mut vec!["i686", "x86_64"]);
+    }
+    // Linux has all x86 targets, plus aarch64 and mips.
+    let mut extra_targets = x86_archs.clone();
+    if llvm_components_contain("aarch64") {
+        extra_targets.push("aarch64");
+    }
+    if llvm_components_contain("mips") {
+        extra_targets.append(&mut vec!["mips", "mipsel"]);
+    }
+
+    for target in extra_targets {
+        let linux = format!("{target}-unknown-linux-gnu");
+        targets.push(linux);
+    }
+
+    // Windows and Darwin (OSX) only receive x86 targets.
+    let extra_targets = x86_archs.clone();
+    for target in extra_targets {
+        let windows = format!("{target}-pc-windows-gnu");
+        let darwin = format!("{target}-apple-darwin");
+        targets.push(windows);
+        targets.push(darwin);
+    }
+
+    for target in targets {
+        // compile the rust file to the given target, but only to asm and IR
+        // form, to avoid having to have an appropriate linker.
+        //
+        // we need some features because the integer SIMD instructions are not
+        // enabled by-default for i686 and ARM; these features will be invalid
+        // on some platforms, but LLVM just prints a warning so that's fine for
+        // now.
+        rustc()
+            .target(&target)
+            .emit("llvm-ir,asm")
+            .input("simd.rs")
+            .arg("-Ctarget-feature=+neon,+sse")
+            .arg(&format!("-Cextra-filename=-{target}"))
+            .run();
+    }
+}
diff --git a/tests/run-make/stable-symbol-names/Makefile b/tests/run-make/stable-symbol-names/Makefile
deleted file mode 100644
index bbfb8e38881..00000000000
--- a/tests/run-make/stable-symbol-names/Makefile
+++ /dev/null
@@ -1,41 +0,0 @@
-include ../tools.mk
-
-# The following command will:
-#  1. dump the symbols of a library using `nm`
-#  2. extract only those lines that we are interested in via `grep`
-#  3. from those lines, extract just the symbol name via `sed`, which:
-#    * always starts with "_ZN" and ends with "E" (`legacy` mangling)
-#    * always starts with "_R" (`v0` mangling)
-#  4. sort those symbol names for deterministic comparison
-#  5. write the result into a file
-
-dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \
-             | grep -E "$(2)" \
-             | sed -E "s/.*(_ZN.*E|_R[a-zA-Z0-9_]*).*/\1/" \
-             | sort \
-             > "$(TMPDIR)/$(1)$(3).nm"
-
-# This test
-# - compiles each of the two crates 2 times and makes sure each time we get
-#   exactly the same symbol names
-# - makes sure that both crates agree on the same symbol names for monomorphic
-#   functions
-
-all:
-	$(RUSTC) stable-symbol-names1.rs
-	$(call dump-symbols,stable_symbol_names1,generic_|mono_,_v1)
-	rm $(TMPDIR)/libstable_symbol_names1.rlib
-	$(RUSTC) stable-symbol-names1.rs
-	$(call dump-symbols,stable_symbol_names1,generic_|mono_,_v2)
-	cmp "$(TMPDIR)/stable_symbol_names1_v1.nm" "$(TMPDIR)/stable_symbol_names1_v2.nm"
-
-	$(RUSTC) stable-symbol-names2.rs
-	$(call dump-symbols,stable_symbol_names2,generic_|mono_,_v1)
-	rm $(TMPDIR)/libstable_symbol_names2.rlib
-	$(RUSTC) stable-symbol-names2.rs
-	$(call dump-symbols,stable_symbol_names2,generic_|mono_,_v2)
-	cmp "$(TMPDIR)/stable_symbol_names2_v1.nm" "$(TMPDIR)/stable_symbol_names2_v2.nm"
-
-	$(call dump-symbols,stable_symbol_names1,mono_,_cross)
-	$(call dump-symbols,stable_symbol_names2,mono_,_cross)
-	cmp "$(TMPDIR)/stable_symbol_names1_cross.nm" "$(TMPDIR)/stable_symbol_names2_cross.nm"
diff --git a/tests/run-make/stable-symbol-names/rmake.rs b/tests/run-make/stable-symbol-names/rmake.rs
new file mode 100644
index 00000000000..402f411c7f5
--- /dev/null
+++ b/tests/run-make/stable-symbol-names/rmake.rs
@@ -0,0 +1,68 @@
+// A typo in rustc caused generic symbol names to be non-deterministic -
+// that is, it was possible to compile the same file twice with no changes
+// and get outputs with different symbol names.
+// This test compiles each of the two crates twice, and checks that each output
+// contains exactly the same symbol names.
+// Additionally, both crates should agree on the same symbol names for monomorphic
+// functions.
+// See https://github.com/rust-lang/rust/issues/32554
+
+use std::collections::HashSet;
+
+use run_make_support::{llvm_readobj, regex, rfs, rust_lib_name, rustc};
+
+static LEGACY_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
+static V0_PATTERN: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
+
+fn main() {
+    LEGACY_PATTERN.set(regex::Regex::new(r"_ZN.*E").unwrap()).unwrap();
+    V0_PATTERN.set(regex::Regex::new(r"_R[a-zA-Z0-9_]*").unwrap()).unwrap();
+    // test 1: first file
+    rustc().input("stable-symbol-names1.rs").run();
+    let sym1 = process_symbols("stable_symbol_names1", "generic_|mono_");
+    rfs::remove_file(rust_lib_name("stable_symbol_names1"));
+    rustc().input("stable-symbol-names1.rs").run();
+    let sym2 = process_symbols("stable_symbol_names1", "generic_|mono_");
+    assert_eq!(sym1, sym2);
+
+    // test 2: second file
+    rustc().input("stable-symbol-names2.rs").run();
+    let sym1 = process_symbols("stable_symbol_names2", "generic_|mono_");
+    rfs::remove_file(rust_lib_name("stable_symbol_names2"));
+    rustc().input("stable-symbol-names2.rs").run();
+    let sym2 = process_symbols("stable_symbol_names2", "generic_|mono_");
+    assert_eq!(sym1, sym2);
+
+    // test 3: crossed files
+    let sym1 = process_symbols("stable_symbol_names1", "mono_");
+    let sym2 = process_symbols("stable_symbol_names2", "mono_");
+    assert_eq!(sym1, sym2);
+}
+
+#[track_caller]
+fn process_symbols(path: &str, symbol: &str) -> Vec<String> {
+    // Dump all symbols.
+    let out = llvm_readobj().input(rust_lib_name(path)).symbols().run().stdout_utf8();
+    // Extract only lines containing `symbol`.
+    let symbol_regex = regex::Regex::new(symbol).unwrap();
+    let out = out.lines().filter(|&line| symbol_regex.find(line).is_some());
+
+    // HashSet - duplicates should be excluded!
+    let mut symbols: HashSet<String> = HashSet::new();
+    // From those lines, extract just the symbol name via `regex`, which:
+    //   * always starts with "_ZN" and ends with "E" (`legacy` mangling)
+    //   * always starts with "_R" (`v0` mangling)
+    for line in out {
+        if let Some(mat) = LEGACY_PATTERN.get().unwrap().find(line) {
+            symbols.insert(mat.as_str().to_string());
+        }
+        if let Some(mat) = V0_PATTERN.get().unwrap().find(line) {
+            symbols.insert(mat.as_str().to_string());
+        }
+    }
+
+    let mut symbols: Vec<String> = symbols.into_iter().collect();
+    // Sort those symbol names for deterministic comparison.
+    symbols.sort();
+    symbols
+}
diff --git a/tests/run-make/staticlib-dylib-linkage/Makefile b/tests/run-make/staticlib-dylib-linkage/Makefile
deleted file mode 100644
index a1e86a7ce4b..00000000000
--- a/tests/run-make/staticlib-dylib-linkage/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-include ../tools.mk
-
-# ignore-cross-compile
-# ignore-msvc FIXME(bjorn3) can't figure out how to link with the MSVC toolchain
-# ignore-wasm wasm doesn't support dynamic libraries
-
-all:
-	$(RUSTC) -C prefer-dynamic bar.rs
-	$(RUSTC) foo.rs --crate-type staticlib --print native-static-libs \
-		-Z staticlib-allow-rdylib-deps 2>&1 | grep 'note: native-static-libs: ' \
-		| sed 's/note: native-static-libs: \(.*\)/\1/' > $(TMPDIR)/libs.txt
-	cat $(TMPDIR)/libs.txt
-
-ifdef IS_MSVC
-	$(CC) $(CFLAGS) /c foo.c /Fo:$(TMPDIR)/foo.o
-	$(RUSTC_LINKER) $(TMPDIR)/foo.o $(TMPDIR)/foo.lib $$(cat $(TMPDIR)/libs.txt) $(call OUT_EXE,foo)
-else
-	$(CC) $(CFLAGS) foo.c -L $(TMPDIR) -lfoo $$(cat $(TMPDIR)/libs.txt) -o $(call RUN_BINFILE,foo)
-endif
-
-	$(call RUN,foo)
diff --git a/tests/run-make/staticlib-dylib-linkage/rmake.rs b/tests/run-make/staticlib-dylib-linkage/rmake.rs
new file mode 100644
index 00000000000..8dd1ac0ffbd
--- /dev/null
+++ b/tests/run-make/staticlib-dylib-linkage/rmake.rs
@@ -0,0 +1,36 @@
+// A basic smoke test to check that rustc supports linking to a rust dylib with
+// --crate-type staticlib. bar is a dylib, on which foo is dependent - the native
+// static lib search paths are collected and used to compile foo.c, the final executable
+// which depends on both foo and bar.
+// See https://github.com/rust-lang/rust/pull/106560
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed.
+//@ ignore-wasm
+// Reason: WASM does not support dynamic libraries
+
+use run_make_support::{cc, is_msvc, regex, run, rustc, static_lib_name};
+
+fn main() {
+    rustc().arg("-Cprefer-dynamic").input("bar.rs").run();
+    let libs = rustc()
+        .input("foo.rs")
+        .crate_type("staticlib")
+        .print("native-static-libs")
+        .arg("-Zstaticlib-allow-rdylib-deps")
+        .run()
+        .assert_stderr_contains("note: native-static-libs: ")
+        .stderr_utf8();
+    let re = regex::Regex::new(r#"note: native-static-libs:\s*(.+)"#).unwrap();
+    let libs = re.find(&libs).unwrap().as_str().trim();
+    // remove the note
+    let (_, native_link_args) = libs.split_once("note: native-static-libs: ").unwrap();
+    // divide the command-line arguments in a vec
+    let mut native_link_args = native_link_args.split(' ').collect::<Vec<&str>>();
+    if is_msvc() {
+        // For MSVC pass the arguments on to the linker.
+        native_link_args.insert(0, "-link");
+    }
+    cc().input("foo.c").input(static_lib_name("foo")).args(native_link_args).out_exe("foo").run();
+    run("foo");
+}
diff --git a/tests/run-make/symbol-visibility/rmake.rs b/tests/run-make/symbol-visibility/rmake.rs
index b37ff44f4ea..f84e63ef74e 100644
--- a/tests/run-make/symbol-visibility/rmake.rs
+++ b/tests/run-make/symbol-visibility/rmake.rs
@@ -4,12 +4,8 @@
 // are exported, and that generics are only shown if explicitely requested.
 // See https://github.com/rust-lang/rust/issues/37530
 
-//@ ignore-windows-msvc
-
-//FIXME(Oneirical): This currently uses llvm-nm for symbol detection. However,
-// the custom Rust-based solution of #128314 may prove to be an interesting alternative.
-
-use run_make_support::{bin_name, dynamic_lib_name, is_darwin, is_windows, llvm_nm, regex, rustc};
+use run_make_support::object::read::Object;
+use run_make_support::{bin_name, dynamic_lib_name, is_msvc, object, regex, rfs, rustc};
 
 fn main() {
     let cdylib_name = dynamic_lib_name("a_cdylib");
@@ -64,16 +60,15 @@ fn main() {
     );
 
     // FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
-    // if is_windows() {
-    //     // Check that an executable does not export any dynamic symbols
-    //     symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib")
-    //, false);
-    //     symbols_check(
-    //         &exe_name,
-    //         SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
-    //         false,
-    //     );
-    // }
+    if is_msvc() {
+        // Check that an executable does not export any dynamic symbols
+        symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
+        symbols_check(
+            &exe_name,
+            SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
+            false,
+        );
+    }
 
     // Check the combined case, where we generate a cdylib and an rlib in the same
     // compilation session:
@@ -131,44 +126,37 @@ fn main() {
     );
 
     // FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032
-    // if is_windows() {
-    //     // Check that an executable does not export any dynamic symbols
-    //     symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib")
-    //, false);
-    //     symbols_check(
-    //         &exe_name,
-    //         SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
-    //         false,
-    //     );
-    // }
+    if is_msvc() {
+        // Check that an executable does not export any dynamic symbols
+        symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false);
+        symbols_check(
+            &exe_name,
+            SymbolCheckType::StrSymbol("public_rust_function_from_exe"),
+            false,
+        );
+    }
 }
 
 #[track_caller]
 fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bool) {
-    let mut nm = llvm_nm();
-    if is_windows() {
-        nm.arg("--extern-only");
-    } else if is_darwin() {
-        nm.arg("--extern-only").arg("--defined-only");
-    } else {
-        nm.arg("--dynamic");
+    let binary_data = rfs::read(path);
+    let file = object::File::parse(&*binary_data).unwrap();
+    let mut found: u64 = 0;
+    for export in file.exports().unwrap() {
+        let name = std::str::from_utf8(export.name()).unwrap();
+        if has_symbol(name, symbol_check_type) {
+            found += 1;
+        }
     }
-    let out = nm.input(path).run().stdout_utf8();
-    assert_eq!(
-        out.lines()
-            .filter(|&line| !line.contains("__imp_") && has_symbol(line, symbol_check_type))
-            .count()
-            == 1,
-        exists_once
-    );
+    assert_eq!(found, exists_once as u64);
 }
 
-fn has_symbol(line: &str, symbol_check_type: SymbolCheckType) -> bool {
+fn has_symbol(name: &str, symbol_check_type: SymbolCheckType) -> bool {
     if let SymbolCheckType::StrSymbol(expected) = symbol_check_type {
-        line.contains(expected)
+        name.contains(expected)
     } else {
         let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap();
-        regex.is_match(line)
+        regex.is_match(name)
     }
 }
 
diff --git a/tests/run-make/thumb-none-cortex-m/Makefile b/tests/run-make/thumb-none-cortex-m/Makefile
deleted file mode 100644
index e941fc4a78e..00000000000
--- a/tests/run-make/thumb-none-cortex-m/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-include ../tools.mk
-
-# How to run this
-# $ ./x.py clean
-# $ ./x.py test --target thumbv6m-none-eabi,thumbv7m-none-eabi tests/run-make
-
-# Supported targets:
-# - thumbv6m-none-eabi (Bare Cortex-M0, M0+, M1)
-# - thumbv7em-none-eabi (Bare Cortex-M4, M7)
-# - thumbv7em-none-eabihf (Bare Cortex-M4F, M7F, FPU, hardfloat)
-# - thumbv7m-none-eabi (Bare Cortex-M3)
-
-# only-thumb
-
-# For cargo setting
-RUSTC := $(RUSTC_ORIGINAL)
-LD_LIBRARY_PATH := $(HOST_RPATH_DIR)
-# We need to be outside of 'src' dir in order to run cargo
-WORK_DIR := $(TMPDIR)
-
-HERE := $(shell pwd)
-
-CRATE := cortex-m
-CRATE_URL := https://github.com/rust-embedded/cortex-m
-CRATE_SHA1 := a448e9156e2cb1e556e5441fd65426952ef4b927 # 0.5.0
-
-# Don't make lints fatal, but they need to at least warn or they break Cargo's target info parsing.
-export RUSTFLAGS := --cap-lints=warn
-
-all:
-	env
-	mkdir -p $(WORK_DIR)
-	-cd $(WORK_DIR) && rm -rf $(CRATE)
-	cd $(WORK_DIR) && bash -x $(HERE)/../git_clone_sha1.sh $(CRATE) $(CRATE_URL) $(CRATE_SHA1)
-	# HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features.
-	# These come from the top-level Rust workspace, that this crate is not a
-	# member of, but Cargo tries to load the workspace `Cargo.toml` anyway.
-	cd $(WORK_DIR) && cd $(CRATE) && env RUSTC_BOOTSTRAP=1 $(BOOTSTRAP_CARGO) build --target $(TARGET) -v
diff --git a/tests/run-make/thumb-none-cortex-m/rmake.rs b/tests/run-make/thumb-none-cortex-m/rmake.rs
new file mode 100644
index 00000000000..0ddb91d378f
--- /dev/null
+++ b/tests/run-make/thumb-none-cortex-m/rmake.rs
@@ -0,0 +1,59 @@
+//! Test building of the `cortex-m` crate, a foundational crate in the embedded ecosystem
+//! for a collection of thumb targets. This is a smoke test that verifies that both cargo
+//! and rustc work in this case.
+//!
+//! How to run this
+//! $ ./x.py clean
+//! $ ./x.py test --target thumbv6m-none-eabi,thumbv7m-none-eabi tests/run-make
+//!
+//! Supported targets:
+//! - thumbv6m-none-eabi (Bare Cortex-M0, M0+, M1)
+//! - thumbv7em-none-eabi (Bare Cortex-M4, M7)
+//! - thumbv7em-none-eabihf (Bare Cortex-M4F, M7F, FPU, hardfloat)
+//! - thumbv7m-none-eabi (Bare Cortex-M3)
+
+//@ only-thumb
+
+use std::path::PathBuf;
+
+use run_make_support::rfs::create_dir;
+use run_make_support::{cmd, env_var, target};
+
+const CRATE: &str = "cortex-m";
+const CRATE_URL: &str = "https://github.com/rust-embedded/cortex-m";
+const CRATE_SHA1: &str = "a448e9156e2cb1e556e5441fd65426952ef4b927"; // v0.5.0
+
+fn main() {
+    // FIXME: requires an internet connection https://github.com/rust-lang/rust/issues/128733
+    // See below link for git usage:
+    // https://stackoverflow.com/questions/3489173#14091182
+    cmd("git").args(["clone", CRATE_URL, CRATE]).run();
+    std::env::set_current_dir(CRATE).unwrap();
+    cmd("git").args(["reset", "--hard", CRATE_SHA1]).run();
+
+    let target_dir = PathBuf::from("target");
+    let manifest_path = PathBuf::from("Cargo.toml");
+
+    let path = env_var("PATH");
+    let rustc = env_var("RUSTC");
+    let bootstrap_cargo = env_var("BOOTSTRAP_CARGO");
+    // FIXME: extract bootstrap cargo invocations to a proper command
+    // https://github.com/rust-lang/rust/issues/128734
+    let mut cmd = cmd(bootstrap_cargo);
+    cmd.args(&[
+        "build",
+        "--manifest-path",
+        manifest_path.to_str().unwrap(),
+        "-Zbuild-std=core",
+        "--target",
+        &target(),
+    ])
+    .env("PATH", path)
+    .env("RUSTC", rustc)
+    .env("CARGO_TARGET_DIR", &target_dir)
+    // Don't make lints fatal, but they need to at least warn
+    // or they break Cargo's target info parsing.
+    .env("RUSTFLAGS", "-Copt-level=0 -Cdebug-assertions=yes --cap-lints=warn");
+
+    cmd.run();
+}
diff --git a/tests/run-make/thumb-none-qemu/Makefile b/tests/run-make/thumb-none-qemu/Makefile
deleted file mode 100644
index eea6ca34992..00000000000
--- a/tests/run-make/thumb-none-qemu/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-include ../tools.mk
-
-# only-thumb
-
-# How to run this
-# $ ./x.py clean
-# $ ./x.py test --target thumbv7m-none-eabi tests/run-make
-
-# For cargo setting
-export RUSTC := $(RUSTC_ORIGINAL)
-export LD_LIBRARY_PATH := $(HOST_RPATH_DIR)
-# We need to be outside of 'src' dir in order to run cargo
-export WORK_DIR := $(TMPDIR)
-export HERE := $(shell pwd)
-
-## clean up unused env variables which might cause harm.
-unexport RUSTC_LINKER
-unexport RUSTC_BOOTSTRAP
-unexport RUST_BUILD_STAGE
-unexport RUST_TEST_THREADS
-unexport RUST_TEST_TMPDIR
-unexport AR
-unexport CC
-unexport CXX
-
-all:
-	bash script.sh
diff --git a/tests/run-make/thumb-none-qemu/example/.cargo/config b/tests/run-make/thumb-none-qemu/example/.cargo/config.toml
index 8b30310e7d4..7152e81b502 100644
--- a/tests/run-make/thumb-none-qemu/example/.cargo/config
+++ b/tests/run-make/thumb-none-qemu/example/.cargo/config.toml
@@ -1,6 +1,5 @@
 [target.thumbv6m-none-eabi]
-# FIXME: Should be Cortex-M0, but Qemu used by CI is too old
-runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
+runner = "qemu-system-arm -cpu cortex-m0 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
 
 [target.thumbv7m-none-eabi]
 runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
@@ -12,7 +11,7 @@ runner = "qemu-system-arm -cpu cortex-m4 -machine lm3s6965evb -nographic -semiho
 runner = "qemu-system-arm -cpu cortex-m4 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
 
 [target.thumbv8m.base-none-eabi]
-# FIXME: Should be the Cortex-M23, bt Qemu does not currently support it
+# FIXME: Should be the Cortex-M23, but Qemu does not currently support it
 runner = "qemu-system-arm -cpu cortex-m33 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
 
 [target.thumbv8m.main-none-eabi]
diff --git a/tests/run-make/thumb-none-qemu/rmake.rs b/tests/run-make/thumb-none-qemu/rmake.rs
new file mode 100644
index 00000000000..d0f42bc8808
--- /dev/null
+++ b/tests/run-make/thumb-none-qemu/rmake.rs
@@ -0,0 +1,62 @@
+//! This test runs a basic application for thumb targets, using the cortex-m crate.
+//!
+//! These targets are very bare-metal: the first instruction the core runs on
+//! power-on is already user code. The cortex-m-rt has to initialize the stack, .data,
+//! .bss, enable the FPU if present, etc.
+//!
+//! This test builds and runs the applications for various thumb targets using qemu.
+//!
+//! How to run this
+//! $ ./x.py clean
+//! $ ./x.py test --target thumbv6m-none-eabi,thumbv7m-none-eabi tests/run-make
+//!
+//! For supported targets, see `example/.cargo/config.toml`
+//!
+//! FIXME: https://github.com/rust-lang/rust/issues/128733 this test uses external
+//! dependencies, and needs an active internet connection
+//!
+//! FIXME: https://github.com/rust-lang/rust/issues/128734 extract bootstrap cargo
+//! to a proper command
+
+//@ only-thumb
+
+use std::path::PathBuf;
+
+use run_make_support::{cmd, env_var, path_helpers, target};
+
+const CRATE: &str = "example";
+
+fn main() {
+    std::env::set_current_dir(CRATE).unwrap();
+
+    let bootstrap_cargo = env_var("BOOTSTRAP_CARGO");
+    let path = env_var("PATH");
+    let rustc = env_var("RUSTC");
+
+    let target_dir = path_helpers::path("target");
+    let manifest_path = path_helpers::path("Cargo.toml");
+
+    let debug = {
+        let mut cmd = cmd(&bootstrap_cargo);
+        cmd.args(&["run", "--target", &target()])
+            .env("RUSTFLAGS", "-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x")
+            .env("CARGO_TARGET_DIR", &target_dir)
+            .env("PATH", &path)
+            .env("RUSTC", &rustc);
+        cmd.run()
+    };
+
+    debug.assert_stdout_contains("x = 42");
+
+    let release = {
+        let mut cmd = cmd(&bootstrap_cargo);
+        cmd.args(&["run", "--release", "--target", &target()])
+            .env("RUSTFLAGS", "-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x")
+            .env("CARGO_TARGET_DIR", &target_dir)
+            .env("PATH", &path)
+            .env("RUSTC", &rustc);
+        cmd.run()
+    };
+
+    release.assert_stdout_contains("x = 42");
+}
diff --git a/tests/run-make/thumb-none-qemu/script.sh b/tests/run-make/thumb-none-qemu/script.sh
deleted file mode 100644
index a8aa72af184..00000000000
--- a/tests/run-make/thumb-none-qemu/script.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-set -exuo pipefail
-
-CRATE=example
-
-env | sort
-mkdir -p $WORK_DIR
-pushd $WORK_DIR
-    rm -rf $CRATE || echo OK
-    cp -a $HERE/example .
-    pushd $CRATE
-        # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features.
-        # These come from the top-level Rust workspace, that this crate is not a
-        # member of, but Cargo tries to load the workspace `Cargo.toml` anyway.
-        env RUSTC_BOOTSTRAP=1 RUSTFLAGS="-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x" \
-            $BOOTSTRAP_CARGO run --target $TARGET           | grep "x = 42"
-        env RUSTC_BOOTSTRAP=1 RUSTFLAGS="-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x" \
-            $BOOTSTRAP_CARGO run --target $TARGET --release | grep "x = 42"
-    popd
-popd
diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs
index 56ef5c6b9cc..39f36b2eea8 100644
--- a/tests/run-make/used/rmake.rs
+++ b/tests/run-make/used/rmake.rs
@@ -4,12 +4,10 @@
 // It comes from #39987 which implements this RFC for the #[used] attribute:
 // https://rust-lang.github.io/rfcs/2386-used.html
 
-//@ ignore-msvc
-
-use run_make_support::{cmd, rustc};
+use run_make_support::rustc;
+use run_make_support::symbols::any_symbol_contains;
 
 fn main() {
     rustc().opt_level("3").emit("obj").input("used.rs").run();
-
-    cmd("nm").arg("used.o").run().assert_stdout_contains("FOO");
+    assert!(any_symbol_contains("used.o", &["FOO"]));
 }
diff --git a/tests/run-make/used/used.rs b/tests/run-make/used/used.rs
index dca0a5e1167..133f8121a8e 100644
--- a/tests/run-make/used/used.rs
+++ b/tests/run-make/used/used.rs
@@ -2,5 +2,3 @@
 
 #[used]
 static FOO: u32 = 0;
-
-static BAR: u32 = 0;
diff --git a/tests/run-make/wasm-override-linker/rmake.rs b/tests/run-make/wasm-override-linker/rmake.rs
index 01bc08e9901..b04edc18eef 100644
--- a/tests/run-make/wasm-override-linker/rmake.rs
+++ b/tests/run-make/wasm-override-linker/rmake.rs
@@ -2,6 +2,10 @@
 // $ RUSTBUILD_FORCE_CLANG_BASED_TESTS=1 ./x.py test tests/run-make/wasm-override-linker/
 
 //@ needs-force-clang-based-tests
+// FIXME(#126180): This test can only run on `x86_64-gnu-debug`, because that CI job sets
+// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
+// name.
+// However, this test does not run at all as its name does not contain "clang".
 
 use run_make_support::{env_var, rustc, target};
 
diff --git a/tests/run-make/zero-extend-abi-param-passing/param_passing.rs b/tests/run-make/zero-extend-abi-param-passing/param_passing.rs
index c11f3cc72bd..addde6b8ee3 100644
--- a/tests/run-make/zero-extend-abi-param-passing/param_passing.rs
+++ b/tests/run-make/zero-extend-abi-param-passing/param_passing.rs
@@ -2,7 +2,7 @@
 // LLVM optimization choices. See additional note below for an
 // example.
 
-#[link(name = "bad")]
+#[link(name = "bad", kind = "static")]
 extern "C" {
     pub fn c_read_value(a: u32, b: u32, c: u32) -> u16;
 }
diff --git a/tests/run-make/zero-extend-abi-param-passing/rmake.rs b/tests/run-make/zero-extend-abi-param-passing/rmake.rs
index aed27f7f5ab..96dbbd0627c 100644
--- a/tests/run-make/zero-extend-abi-param-passing/rmake.rs
+++ b/tests/run-make/zero-extend-abi-param-passing/rmake.rs
@@ -6,20 +6,13 @@
 // while simultaneously interfacing with a C library and using the -O3 flag.
 // See https://github.com/rust-lang/rust/issues/97463
 
-//@ ignore-msvc
-// Reason: the rustc compilation fails due to an unresolved external symbol
-
 //@ ignore-cross-compile
 // Reason: The compiled binary is executed.
-
-use run_make_support::{cc, is_msvc, llvm_ar, run, rustc, static_lib_name};
+use run_make_support::{build_native_static_lib_optimized, run, rustc};
 
 fn main() {
-    // The issue exercised by this test specifically needs needs `-O`
-    // flags (like `-O3`) to reproduce. Thus, we call `cc()` instead of
-    // the nicer `build_native_static_lib`.
-    cc().arg("-c").arg("-O3").out_exe("bad.o").input("bad.c").run();
-    llvm_ar().obj_to_ar().output_input(static_lib_name("bad"), "bad.o").run();
-    rustc().input("param_passing.rs").arg("-lbad").opt_level("3").run();
+    // The issue exercised by this test specifically needs an optimized native static lib.
+    build_native_static_lib_optimized("bad");
+    rustc().input("param_passing.rs").opt_level("3").run();
     run("param_passing");
 }
diff --git a/tests/rustdoc-gui/search-result-impl-disambiguation.goml b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
index 3e49ac33025..bca52b46498 100644
--- a/tests/rustdoc-gui/search-result-impl-disambiguation.goml
+++ b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
@@ -41,3 +41,24 @@ assert-document-property: ({
     "URL": "struct.ZyxwvutMethodDisambiguation.html#method.method_impl_disambiguation-1"
 }, ENDS_WITH)
 assert: "section:target"
+
+// Checks that, if a type has two methods with the same name,
+// and if it has multiple inherent impl blocks, that the numeric
+// impl block's disambiguator is also acted upon.
+go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=MultiImplBlockStruct->bool"
+wait-for: "#search-tabs"
+assert-count: ("a.result-method", 1)
+assert-attribute: ("a.result-method", {
+    "href": "../lib2/another_mod/struct.MultiImplBlockStruct.html#impl-MultiImplBlockStruct/method.second_fn"
+})
+click: "a.result-method"
+wait-for: "details:has(summary > #impl-MultiImplBlockStruct-1) > div section[id='method.second_fn']:target"
+
+go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=MultiImplBlockStruct->u32"
+wait-for: "#search-tabs"
+assert-count: ("a.result-method", 1)
+assert-attribute: ("a.result-method", {
+    "href": "../lib2/another_mod/struct.MultiImplBlockStruct.html#impl-MultiImplBlockTrait-for-MultiImplBlockStruct/method.second_fn"
+})
+click: "a.result-method"
+wait-for: "details:has(summary > #impl-MultiImplBlockTrait-for-MultiImplBlockStruct) > div section[id='method.second_fn-1']:target"
diff --git a/tests/rustdoc-gui/src/lib2/another_mod/mod.rs b/tests/rustdoc-gui/src/lib2/another_mod/mod.rs
index 9a4f007a2f0..77f83d29766 100644
--- a/tests/rustdoc-gui/src/lib2/another_mod/mod.rs
+++ b/tests/rustdoc-gui/src/lib2/another_mod/mod.rs
@@ -1 +1,19 @@
-pub fn tadam() {}
+pub struct MultiImplBlockStruct;
+
+impl MultiImplBlockStruct {
+    pub fn first_fn() {}
+}
+
+impl MultiImplBlockStruct {
+    pub fn second_fn(self) -> bool { true }
+}
+
+pub trait MultiImplBlockTrait {
+    fn first_fn();
+    fn second_fn(self) -> u32;
+}
+
+impl MultiImplBlockTrait for MultiImplBlockStruct {
+    fn first_fn() {}
+    fn second_fn(self) -> u32 { 1 }
+}
diff --git a/tests/rustdoc-js/self-is-not-generic.js b/tests/rustdoc-js/self-is-not-generic.js
new file mode 100644
index 00000000000..0fdf5b4117d
--- /dev/null
+++ b/tests/rustdoc-js/self-is-not-generic.js
@@ -0,0 +1,22 @@
+// exact-check
+
+const EXPECTED = [
+    {
+        'query': 'A -> A',
+        'others': [
+            { 'path': 'self_is_not_generic::Thing', 'name': 'from' }
+        ],
+    },
+    {
+        'query': 'A -> B',
+        'others': [
+            { 'path': 'self_is_not_generic::Thing', 'name': 'try_from' }
+        ],
+    },
+    {
+        'query': 'Combine -> Combine',
+        'others': [
+            { 'path': 'self_is_not_generic::Combine', 'name': 'combine' }
+        ],
+    }
+];
diff --git a/tests/rustdoc-js/self-is-not-generic.rs b/tests/rustdoc-js/self-is-not-generic.rs
new file mode 100644
index 00000000000..d6a96acb73c
--- /dev/null
+++ b/tests/rustdoc-js/self-is-not-generic.rs
@@ -0,0 +1,11 @@
+pub trait Combine {
+    fn combine(&self, other: &Self) -> Self;
+}
+
+pub struct Thing;
+
+impl Combine for Thing {
+    fn combine(&self, other: &Self) -> Self {
+        Self
+    }
+}
diff --git a/tests/rustdoc-json/impls/pub_for_hidden_private.rs b/tests/rustdoc-json/impls/pub_for_hidden_private.rs
new file mode 100644
index 00000000000..261ffbfeb4a
--- /dev/null
+++ b/tests/rustdoc-json/impls/pub_for_hidden_private.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: --document-private-items --document-hidden-items
+
+pub trait TheTrait {}
+
+#[doc(hidden)]
+struct Value {}
+
+//@ has '$.index[*][?(@.docs=="THE IMPL")]'
+/// THE IMPL
+impl TheTrait for Value {}
diff --git a/tests/rustdoc-json/pub_mod_in_private_mod.rs b/tests/rustdoc-json/pub_mod_in_private_mod.rs
new file mode 100644
index 00000000000..112ab9c68f0
--- /dev/null
+++ b/tests/rustdoc-json/pub_mod_in_private_mod.rs
@@ -0,0 +1,6 @@
+// See https://github.com/rust-lang/rust/issues/101105
+
+//@ !has "$.index[*][?(@.name=='nucleus')]"
+mod corpus {
+    pub mod nucleus {}
+}
diff --git a/tests/rustdoc-json/the_smallest.rs b/tests/rustdoc-json/the_smallest.rs
new file mode 100644
index 00000000000..2f6f91e6e27
--- /dev/null
+++ b/tests/rustdoc-json/the_smallest.rs
@@ -0,0 +1,5 @@
+// This test asserts that `index` is not polluted with unrelated items.
+// See https://github.com/rust-lang/rust/issues/114039
+
+//@ count "$.index[*]" 1
+fn main() {}
diff --git a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs
new file mode 100644
index 00000000000..571bc94e30f
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs
@@ -0,0 +1,12 @@
+//@ compile-flags:--test
+//@ check-pass
+#![allow(rustdoc::invalid_codeblock_attributes)]
+
+// https://github.com/rust-lang/rust/pull/124577#issuecomment-2276034737
+
+// Test that invalid langstrings don't get run.
+
+/// ```{rust,ignore}
+/// panic!();
+/// ```
+pub struct Foo;
diff --git a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout
new file mode 100644
index 00000000000..e5c27bebbdb
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout
@@ -0,0 +1,5 @@
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+
diff --git a/tests/rustdoc-ui/intra-doc/.gitattributes b/tests/rustdoc-ui/intra-doc/.gitattributes
index 6c125fac52f..0ac2e3c27f4 100644
--- a/tests/rustdoc-ui/intra-doc/.gitattributes
+++ b/tests/rustdoc-ui/intra-doc/.gitattributes
@@ -1 +1 @@
-warning-crlf.rs eol=crlf
+warning-crlf.rs -text
diff --git a/tests/rustdoc-ui/intra-doc/warning-crlf.rs b/tests/rustdoc-ui/intra-doc/warning-crlf.rs
index ab096b860f8..9d3a4673c9d 100644
--- a/tests/rustdoc-ui/intra-doc/warning-crlf.rs
+++ b/tests/rustdoc-ui/intra-doc/warning-crlf.rs
@@ -1,26 +1,26 @@
-// ignore-tidy-cr
-//@ check-pass
-
-// This file checks the spans of intra-link warnings in a file with CRLF line endings. The
-// .gitattributes file in this directory should enforce it.
-
-/// [error]
-pub struct A;
-//~^^ WARNING `error`
-
-///
-/// docs [error1]
-//~^ WARNING `error1`
-
-/// docs [error2]
-///
-pub struct B;
-//~^^^ WARNING `error2`
-
-/**
- * This is a multi-line comment.
- *
- * It also has an [error].
- */
-pub struct C;
-//~^^^ WARNING `error`
+// ignore-tidy-cr

+//@ check-pass

+

+// This file checks the spans of intra-link warnings in a file with CRLF line endings. The

+// .gitattributes file in this directory should enforce it.

+

+/// [error]

+pub struct A;

+//~^^ WARNING `error`

+

+///

+/// docs [error1]

+//~^ WARNING `error1`

+

+/// docs [error2]

+///

+pub struct B;

+//~^^^ WARNING `error2`

+

+/**

+ * This is a multi-line comment.

+ *

+ * It also has an [error].

+ */

+pub struct C;

+//~^^^ WARNING `error`

diff --git a/tests/rustdoc-ui/issues/issue-81662-shortness.rs b/tests/rustdoc-ui/issues/issue-81662-shortness.rs
index 02207d2a736..7df63261ce7 100644
--- a/tests/rustdoc-ui/issues/issue-81662-shortness.rs
+++ b/tests/rustdoc-ui/issues/issue-81662-shortness.rs
@@ -1,6 +1,6 @@
 //@ compile-flags:--test --error-format=short
 //@ check-stdout
-//@ error-pattern:cannot find function `foo` in this scope
+//@ error-pattern:cannot find function `foo`
 //@ normalize-stdout-test: "tests/rustdoc-ui/issues" -> "$$DIR"
 //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ failure-status: 101
diff --git a/tests/rustdoc-ui/issues/issue-81662-shortness.stdout b/tests/rustdoc-ui/issues/issue-81662-shortness.stdout
index f32f51e12f2..8fcc7ed272f 100644
--- a/tests/rustdoc-ui/issues/issue-81662-shortness.stdout
+++ b/tests/rustdoc-ui/issues/issue-81662-shortness.stdout
@@ -5,7 +5,7 @@ test $DIR/issue-81662-shortness.rs - foo (line 8) ... FAILED
 failures:
 
 ---- $DIR/issue-81662-shortness.rs - foo (line 8) stdout ----
-$DIR/issue-81662-shortness.rs:9:1: error[E0425]: cannot find function `foo` in this scope
+$DIR/issue-81662-shortness.rs:9:1: error[E0425]: cannot find function `foo` in this scope: not found in this scope
 error: aborting due to 1 previous error
 Couldn't compile the test.
 
diff --git a/tests/rustdoc-ui/remap-path-prefix-lint.rs b/tests/rustdoc-ui/remap-path-prefix-lint.rs
new file mode 100644
index 00000000000..f27863e825d
--- /dev/null
+++ b/tests/rustdoc-ui/remap-path-prefix-lint.rs
@@ -0,0 +1,10 @@
+// Regression test for remapped paths in rustdoc errors
+// <https://github.com/rust-lang/rust/issues/69264>.
+
+//@ compile-flags:-Z unstable-options --remap-path-prefix={{src-base}}=remapped_path
+//@ rustc-env:RUST_BACKTRACE=0
+
+#![deny(rustdoc::invalid_html_tags)]
+
+/// </script>
+pub struct Bar;
diff --git a/tests/rustdoc-ui/remap-path-prefix-lint.stderr b/tests/rustdoc-ui/remap-path-prefix-lint.stderr
new file mode 100644
index 00000000000..d7c1bb1965d
--- /dev/null
+++ b/tests/rustdoc-ui/remap-path-prefix-lint.stderr
@@ -0,0 +1,14 @@
+error: unopened HTML tag `script`
+  --> remapped_path/remap-path-prefix-lint.rs:9:5
+   |
+LL | /// </script>
+   |     ^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> remapped_path/remap-path-prefix-lint.rs:7:9
+   |
+LL | #![deny(rustdoc::invalid_html_tags)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs b/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs
new file mode 100644
index 00000000000..5d0881029cb
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs
@@ -0,0 +1,2 @@
+//@ build-aux-docs
+pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs b/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs
new file mode 100644
index 00000000000..fab9ec4a92b
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs
@@ -0,0 +1,4 @@
+//@ aux-build:q.rs
+//@ build-aux-docs
+extern crate q;
+pub trait Tango {}
diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs b/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs
new file mode 100644
index 00000000000..85c460ace64
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs
@@ -0,0 +1,16 @@
+//@ aux-build:t.rs
+//@ build-aux-docs
+//@ has q/struct.Quebec.html
+//@ has s/struct.Sierra.html
+//@ has t/trait.Tango.html
+//@ hasraw s/struct.Sierra.html 'Tango'
+//@ hasraw trait.impl/t/trait.Tango.js 'struct.Sierra.html'
+//@ hasraw search-index.js 'Tango'
+//@ hasraw search-index.js 'Sierra'
+//@ hasraw search-index.js 'Quebec'
+
+// We document multiple crates into the same output directory, which
+// merges the cross-crate information. Everything is available.
+extern crate t;
+pub struct Sierra;
+impl t::Tango for Sierra {}
diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/q.rs b/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/q.rs
new file mode 100644
index 00000000000..932a0b17206
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/q.rs
@@ -0,0 +1,5 @@
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/t.rs b/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/t.rs
new file mode 100644
index 00000000000..c21a59c6518
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/t.rs
@@ -0,0 +1,7 @@
+//@ aux-build:q.rs
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+extern crate q;
+pub trait Tango {}
diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs b/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs
new file mode 100644
index 00000000000..68bfc34883b
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs
@@ -0,0 +1,24 @@
+//@ aux-build:t.rs
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+//@ has index.html
+//@ has index.html '//h1' 'List of all crates'
+//@ has index.html '//ul[@class="all-items"]//a[@href="q/index.html"]' 'q'
+//@ has index.html '//ul[@class="all-items"]//a[@href="s/index.html"]' 's'
+//@ has index.html '//ul[@class="all-items"]//a[@href="t/index.html"]' 't'
+//@ has q/struct.Quebec.html
+//@ has s/struct.Sierra.html
+//@ has t/trait.Tango.html
+//@ hasraw s/struct.Sierra.html 'Tango'
+//@ hasraw trait.impl/t/trait.Tango.js 'struct.Sierra.html'
+//@ hasraw search-index.js 'Tango'
+//@ hasraw search-index.js 'Sierra'
+//@ hasraw search-index.js 'Quebec'
+
+// We document multiple crates into the same output directory, which
+// merges the cross-crate information. Everything is available.
+extern crate t;
+pub struct Sierra;
+impl t::Tango for Sierra {}
diff --git a/tests/rustdoc/cross-crate-info/cargo-two-no-index/auxiliary/f.rs b/tests/rustdoc/cross-crate-info/cargo-two-no-index/auxiliary/f.rs
new file mode 100644
index 00000000000..abc580a388c
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-two-no-index/auxiliary/f.rs
@@ -0,0 +1,2 @@
+//@ build-aux-docs
+pub trait Foxtrot {}
diff --git a/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs b/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs
new file mode 100644
index 00000000000..c93298f969e
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs
@@ -0,0 +1,14 @@
+//@ aux-build:f.rs
+//@ build-aux-docs
+//@ has e/enum.Echo.html
+//@ has f/trait.Foxtrot.html
+//@ hasraw e/enum.Echo.html 'Foxtrot'
+//@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
+//@ hasraw search-index.js 'Foxtrot'
+//@ hasraw search-index.js 'Echo'
+
+// document two crates in the same way that cargo does. do not provide
+// --enable-index-page
+extern crate f;
+pub enum Echo {}
+impl f::Foxtrot for Echo {}
diff --git a/tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs b/tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs
new file mode 100644
index 00000000000..a2a7033b131
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs
@@ -0,0 +1,5 @@
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+pub trait Foxtrot {}
diff --git a/tests/rustdoc/cross-crate-info/cargo-two/e.rs b/tests/rustdoc/cross-crate-info/cargo-two/e.rs
new file mode 100644
index 00000000000..00f86cbc348
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/cargo-two/e.rs
@@ -0,0 +1,21 @@
+//@ aux-build:f.rs
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+//@ has index.html
+//@ has index.html '//h1' 'List of all crates'
+//@ has index.html '//ul[@class="all-items"]//a[@href="f/index.html"]' 'f'
+//@ has index.html '//ul[@class="all-items"]//a[@href="e/index.html"]' 'e'
+//@ has e/enum.Echo.html
+//@ has f/trait.Foxtrot.html
+//@ hasraw e/enum.Echo.html 'Foxtrot'
+//@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
+//@ hasraw search-index.js 'Foxtrot'
+//@ hasraw search-index.js 'Echo'
+
+// document two crates in the same way that cargo does, writing them both
+// into the same output directory
+extern crate f;
+pub enum Echo {}
+impl f::Foxtrot for Echo {}
diff --git a/tests/rustdoc/cross-crate-info/index-on-last/auxiliary/f.rs b/tests/rustdoc/cross-crate-info/index-on-last/auxiliary/f.rs
new file mode 100644
index 00000000000..abc580a388c
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/index-on-last/auxiliary/f.rs
@@ -0,0 +1,2 @@
+//@ build-aux-docs
+pub trait Foxtrot {}
diff --git a/tests/rustdoc/cross-crate-info/index-on-last/e.rs b/tests/rustdoc/cross-crate-info/index-on-last/e.rs
new file mode 100644
index 00000000000..ffee898cd96
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/index-on-last/e.rs
@@ -0,0 +1,20 @@
+//@ aux-build:f.rs
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+//@ has index.html
+//@ has index.html '//h1' 'List of all crates'
+//@ has index.html '//ul[@class="all-items"]//a[@href="f/index.html"]' 'f'
+//@ has index.html '//ul[@class="all-items"]//a[@href="e/index.html"]' 'e'
+//@ has e/enum.Echo.html
+//@ has f/trait.Foxtrot.html
+//@ hasraw e/enum.Echo.html 'Foxtrot'
+//@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
+//@ hasraw search-index.js 'Foxtrot'
+//@ hasraw search-index.js 'Echo'
+
+// only declare --enable-index-page to the last rustdoc invocation
+extern crate f;
+pub enum Echo {}
+impl f::Foxtrot for Echo {}
diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/q.rs b/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/q.rs
new file mode 100644
index 00000000000..932a0b17206
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/q.rs
@@ -0,0 +1,5 @@
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/r.rs b/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/r.rs
new file mode 100644
index 00000000000..2c0db2abc53
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/r.rs
@@ -0,0 +1,7 @@
+//@ aux-build:s.rs
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+extern crate s;
+pub type Romeo = s::Sierra;
diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/s.rs b/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/s.rs
new file mode 100644
index 00000000000..355d3f1aaa8
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/s.rs
@@ -0,0 +1,8 @@
+//@ aux-build:t.rs
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+extern crate t;
+pub struct Sierra;
+impl t::Tango for Sierra {}
diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/t.rs b/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/t.rs
new file mode 100644
index 00000000000..c21a59c6518
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/t.rs
@@ -0,0 +1,7 @@
+//@ aux-build:q.rs
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+extern crate q;
+pub trait Tango {}
diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs b/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs
new file mode 100644
index 00000000000..bcb9464795a
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs
@@ -0,0 +1,30 @@
+//@ aux-build:r.rs
+//@ aux-build:q.rs
+//@ aux-build:t.rs
+//@ aux-build:s.rs
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+//@ has index.html '//h1' 'List of all crates'
+//@ has index.html
+//@ has index.html '//ul[@class="all-items"]//a[@href="i/index.html"]' 'i'
+//@ has index.html '//ul[@class="all-items"]//a[@href="q/index.html"]' 'q'
+//@ has index.html '//ul[@class="all-items"]//a[@href="r/index.html"]' 'r'
+//@ has index.html '//ul[@class="all-items"]//a[@href="s/index.html"]' 's'
+//@ has index.html '//ul[@class="all-items"]//a[@href="t/index.html"]' 't'
+//@ has q/struct.Quebec.html
+//@ has r/type.Romeo.html
+//@ has s/struct.Sierra.html
+//@ has t/trait.Tango.html
+//@ hasraw s/struct.Sierra.html 'Tango'
+//@ hasraw trait.impl/t/trait.Tango.js 'struct.Sierra.html'
+//@ hasraw search-index.js 'Quebec'
+//@ hasraw search-index.js 'Romeo'
+//@ hasraw search-index.js 'Sierra'
+//@ hasraw search-index.js 'Tango'
+//@ has type.impl/s/struct.Sierra.js
+//@ hasraw type.impl/s/struct.Sierra.js 'Tango'
+//@ hasraw type.impl/s/struct.Sierra.js 'Romeo'
+
+// document everything in the default mode
diff --git a/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs b/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs
new file mode 100644
index 00000000000..c5e3dc0a0f4
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs
@@ -0,0 +1,12 @@
+//@ build-aux-docs
+//@ doc-flags:--enable-index-page
+//@ doc-flags:-Zunstable-options
+
+//@ has index.html
+//@ has index.html '//h1' 'List of all crates'
+//@ has index.html '//ul[@class="all-items"]//a[@href="q/index.html"]' 'q'
+//@ has q/struct.Quebec.html
+//@ hasraw search-index.js 'Quebec'
+
+// there's nothing cross-crate going on here
+pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs b/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs
new file mode 100644
index 00000000000..d3e71fa0ce3
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs
@@ -0,0 +1,6 @@
+//@ build-aux-docs
+//@ has q/struct.Quebec.html
+//@ hasraw search-index.js 'Quebec'
+
+// there's nothing cross-crate going on here
+pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/transitive/auxiliary/q.rs b/tests/rustdoc/cross-crate-info/transitive/auxiliary/q.rs
new file mode 100644
index 00000000000..5d0881029cb
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/transitive/auxiliary/q.rs
@@ -0,0 +1,2 @@
+//@ build-aux-docs
+pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/transitive/auxiliary/t.rs b/tests/rustdoc/cross-crate-info/transitive/auxiliary/t.rs
new file mode 100644
index 00000000000..fab9ec4a92b
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/transitive/auxiliary/t.rs
@@ -0,0 +1,4 @@
+//@ aux-build:q.rs
+//@ build-aux-docs
+extern crate q;
+pub trait Tango {}
diff --git a/tests/rustdoc/cross-crate-info/transitive/s.rs b/tests/rustdoc/cross-crate-info/transitive/s.rs
new file mode 100644
index 00000000000..0a4e5f646dd
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/transitive/s.rs
@@ -0,0 +1,6 @@
+//@ aux-build:t.rs
+//@ build-aux-docs
+// simple test to see if we support building transitive crates
+extern crate t;
+pub struct Sierra;
+impl t::Tango for Sierra {}
diff --git a/tests/rustdoc/cross-crate-info/two/auxiliary/f.rs b/tests/rustdoc/cross-crate-info/two/auxiliary/f.rs
new file mode 100644
index 00000000000..abc580a388c
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/two/auxiliary/f.rs
@@ -0,0 +1,2 @@
+//@ build-aux-docs
+pub trait Foxtrot {}
diff --git a/tests/rustdoc/cross-crate-info/two/e.rs b/tests/rustdoc/cross-crate-info/two/e.rs
new file mode 100644
index 00000000000..9665af62706
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/two/e.rs
@@ -0,0 +1,6 @@
+//@ aux-build:f.rs
+//@ build-aux-docs
+// simple test to assert that we can do a two-level aux-build
+extern crate f;
+pub enum Echo {}
+impl f::Foxtrot for Echo {}
diff --git a/tests/rustdoc/cross-crate-info/working-dir-examples/q.rs b/tests/rustdoc/cross-crate-info/working-dir-examples/q.rs
new file mode 100644
index 00000000000..a7ab062fd9e
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/working-dir-examples/q.rs
@@ -0,0 +1,10 @@
+//@ build-aux-docs
+//@ doc-flags:--scrape-examples-output-path=examples
+//@ doc-flags:--scrape-examples-target-crate=q
+//@ doc-flags:-Zunstable-options
+
+//@ has examples
+
+// where will --scrape-examples-output-path resolve the path to be?
+// should be the root output directory
+pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs b/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs
new file mode 100644
index 00000000000..f8c9adcaf9c
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs
@@ -0,0 +1,3 @@
+//@ build-aux-docs
+//@ unique-doc-out-dir
+pub trait Foxtrot {}
diff --git a/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs b/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs
new file mode 100644
index 00000000000..9dcec211e17
--- /dev/null
+++ b/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs
@@ -0,0 +1,14 @@
+//@ aux-build:f.rs
+//@ build-aux-docs
+//@ has e/enum.Echo.html
+//@ !has f/trait.Foxtrot.html
+//@ hasraw e/enum.Echo.html 'Foxtrot'
+//@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
+//@ !hasraw search-index.js 'Foxtrot'
+//@ hasraw search-index.js 'Echo'
+
+// test the fact that our test runner will document this crate somewhere
+// else
+extern crate f;
+pub enum Echo {}
+impl f::Foxtrot for Echo {}
diff --git a/tests/rustdoc/negative-impl-no-items.rs b/tests/rustdoc/negative-impl-no-items.rs
new file mode 100644
index 00000000000..c628e542033
--- /dev/null
+++ b/tests/rustdoc/negative-impl-no-items.rs
@@ -0,0 +1,26 @@
+// This test ensures that negative impls don't have items listed inside them.
+
+#![feature(negative_impls)]
+#![crate_name = "foo"]
+
+pub struct Thing;
+
+//@ has 'foo/struct.Thing.html'
+// We check the full path to ensure there is no `<details>` element.
+//@ has - '//div[@id="trait-implementations-list"]/section[@id="impl-Iterator-for-Thing"]/h3' \
+// 'impl !Iterator for Thing'
+impl !Iterator for Thing {}
+
+// This struct will allow us to compare both paths.
+pub struct Witness;
+
+//@ has 'foo/struct.Witness.html'
+//@ has - '//div[@id="trait-implementations-list"]/details//section[@id="impl-Iterator-for-Witness"]/h3' \
+// 'impl Iterator for Witness'
+impl Iterator for Witness {
+    type Item = u8;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        None
+    }
+}
diff --git a/tests/rustdoc/unsafe-extern-blocks.rs b/tests/rustdoc/unsafe-extern-blocks.rs
index 22d3beea6c3..829095f300f 100644
--- a/tests/rustdoc/unsafe-extern-blocks.rs
+++ b/tests/rustdoc/unsafe-extern-blocks.rs
@@ -1,6 +1,5 @@
 // Test to ensure the feature is working as expected.
 
-#![feature(unsafe_extern_blocks)]
 #![crate_name = "foo"]
 
 // @has 'foo/index.html'
@@ -13,7 +12,7 @@
 // @count - '//ul[@class="item-table"]//sup[@title="unsafe function"]' 1
 // @has - '//ul[@class="item-table"]//sup[@title="unsafe function"]' '⚠'
 
-unsafe extern {
+unsafe extern "C" {
     // @has 'foo/static.FOO.html'
     // @has - '//pre[@class="rust item-decl"]' 'pub static FOO: i32'
     pub safe static FOO: i32;
diff --git a/tests/ui/asm/aarch64/type-check-2.rs b/tests/ui/asm/aarch64/type-check-2.rs
index ba68cdd26d9..46667ae3a65 100644
--- a/tests/ui/asm/aarch64/type-check-2.rs
+++ b/tests/ui/asm/aarch64/type-check-2.rs
@@ -15,15 +15,6 @@ fn main() {
     unsafe {
         // Inputs must be initialized
 
-        // Sym operands must point to a function or static
-
-        const C: i32 = 0;
-        static S: i32 = 0;
-        asm!("{}", sym S);
-        asm!("{}", sym main);
-        asm!("{}", sym C);
-        //~^ ERROR invalid `sym` operand
-
         // Register operands must be Copy
 
         asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
@@ -65,12 +56,3 @@ fn main() {
         asm!("{}", in(reg) u);
     }
 }
-
-// Sym operands must point to a function or static
-
-const C: i32 = 0;
-static S: i32 = 0;
-global_asm!("{}", sym S);
-global_asm!("{}", sym main);
-global_asm!("{}", sym C);
-//~^ ERROR invalid `sym` operand
diff --git a/tests/ui/asm/aarch64/type-check-2.stderr b/tests/ui/asm/aarch64/type-check-2.stderr
index d647f6a9f06..b7723fc74d4 100644
--- a/tests/ui/asm/aarch64/type-check-2.stderr
+++ b/tests/ui/asm/aarch64/type-check-2.stderr
@@ -1,29 +1,13 @@
-error: invalid `sym` operand
-  --> $DIR/type-check-2.rs:75:19
-   |
-LL | global_asm!("{}", sym C);
-   |                   ^^^^^ is an `i32`
-   |
-   = help: `sym` operands must refer to either a function or a static
-
-error: invalid `sym` operand
-  --> $DIR/type-check-2.rs:24:20
-   |
-LL |         asm!("{}", sym C);
-   |                    ^^^^^ is an `i32`
-   |
-   = help: `sym` operands must refer to either a function or a static
-
 error: arguments for inline assembly must be copyable
-  --> $DIR/type-check-2.rs:29:31
+  --> $DIR/type-check-2.rs:20:31
    |
 LL |         asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `SimdNonCopy` does not implement the Copy trait
 
-error: cannot use value of type `{closure@$DIR/type-check-2.rs:41:28: 41:36}` for inline assembly
-  --> $DIR/type-check-2.rs:41:28
+error: cannot use value of type `{closure@$DIR/type-check-2.rs:32:28: 32:36}` for inline assembly
+  --> $DIR/type-check-2.rs:32:28
    |
 LL |         asm!("{}", in(reg) |x: i32| x);
    |                            ^^^^^^^^^^
@@ -31,7 +15,7 @@ LL |         asm!("{}", in(reg) |x: i32| x);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `Vec<i32>` for inline assembly
-  --> $DIR/type-check-2.rs:43:28
+  --> $DIR/type-check-2.rs:34:28
    |
 LL |         asm!("{}", in(reg) vec![0]);
    |                            ^^^^^^^
@@ -40,7 +24,7 @@ LL |         asm!("{}", in(reg) vec![0]);
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: cannot use value of type `(i32, i32, i32)` for inline assembly
-  --> $DIR/type-check-2.rs:45:28
+  --> $DIR/type-check-2.rs:36:28
    |
 LL |         asm!("{}", in(reg) (1, 2, 3));
    |                            ^^^^^^^^^
@@ -48,7 +32,7 @@ LL |         asm!("{}", in(reg) (1, 2, 3));
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `[i32; 3]` for inline assembly
-  --> $DIR/type-check-2.rs:47:28
+  --> $DIR/type-check-2.rs:38:28
    |
 LL |         asm!("{}", in(reg) [1, 2, 3]);
    |                            ^^^^^^^^^
@@ -56,7 +40,7 @@ LL |         asm!("{}", in(reg) [1, 2, 3]);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `fn() {main}` for inline assembly
-  --> $DIR/type-check-2.rs:55:31
+  --> $DIR/type-check-2.rs:46:31
    |
 LL |         asm!("{}", inout(reg) f);
    |                               ^
@@ -64,12 +48,12 @@ LL |         asm!("{}", inout(reg) f);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `&mut i32` for inline assembly
-  --> $DIR/type-check-2.rs:58:31
+  --> $DIR/type-check-2.rs:49:31
    |
 LL |         asm!("{}", inout(reg) r);
    |                               ^
    |
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/asm/invalid-const-operand.rs b/tests/ui/asm/invalid-const-operand.rs
new file mode 100644
index 00000000000..eff335ff6aa
--- /dev/null
+++ b/tests/ui/asm/invalid-const-operand.rs
@@ -0,0 +1,51 @@
+//@ needs-asm-support
+//@ ignore-nvptx64
+//@ ignore-spirv
+
+#![feature(asm_const)]
+
+use std::arch::{asm, global_asm};
+
+// Const operands must be integers and must be constants.
+
+global_asm!("{}", const 0);
+global_asm!("{}", const 0i32);
+global_asm!("{}", const 0i128);
+global_asm!("{}", const 0f32);
+//~^ ERROR invalid type for `const` operand
+global_asm!("{}", const 0 as *mut u8);
+//~^ ERROR invalid type for `const` operand
+
+fn main() {
+    unsafe {
+        // Const operands must be integers and must be constants.
+
+        asm!("{}", const 0);
+        asm!("{}", const 0i32);
+        asm!("{}", const 0i128);
+        asm!("{}", const 0f32);
+        //~^ ERROR invalid type for `const` operand
+        asm!("{}", const 0 as *mut u8);
+        //~^ ERROR invalid type for `const` operand
+        asm!("{}", const &0);
+        //~^ ERROR invalid type for `const` operand
+
+        // Constants must be... constant
+
+        let x = 0;
+        const fn const_foo(x: i32) -> i32 {
+            x
+        }
+        const fn const_bar<T>(x: T) -> T {
+            x
+        }
+        asm!("{}", const x);
+        //~^ ERROR attempt to use a non-constant value in a constant
+        asm!("{}", const const_foo(0));
+        asm!("{}", const const_foo(x));
+        //~^ ERROR attempt to use a non-constant value in a constant
+        asm!("{}", const const_bar(0));
+        asm!("{}", const const_bar(x));
+        //~^ ERROR attempt to use a non-constant value in a constant
+    }
+}
diff --git a/tests/ui/asm/invalid-const-operand.stderr b/tests/ui/asm/invalid-const-operand.stderr
new file mode 100644
index 00000000000..a6d742b53c2
--- /dev/null
+++ b/tests/ui/asm/invalid-const-operand.stderr
@@ -0,0 +1,86 @@
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/invalid-const-operand.rs:42:26
+   |
+LL |         asm!("{}", const x);
+   |                          ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |         const x: /* Type */ = 0;
+   |         ~~~~~  ++++++++++++
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/invalid-const-operand.rs:45:36
+   |
+LL |         asm!("{}", const const_foo(x));
+   |                                    ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |         const x: /* Type */ = 0;
+   |         ~~~~~  ++++++++++++
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/invalid-const-operand.rs:48:36
+   |
+LL |         asm!("{}", const const_bar(x));
+   |                                    ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |         const x: /* Type */ = 0;
+   |         ~~~~~  ++++++++++++
+
+error: invalid type for `const` operand
+  --> $DIR/invalid-const-operand.rs:14:19
+   |
+LL | global_asm!("{}", const 0f32);
+   |                   ^^^^^^----
+   |                         |
+   |                         is an `f32`
+   |
+   = help: `const` operands must be of an integer type
+
+error: invalid type for `const` operand
+  --> $DIR/invalid-const-operand.rs:16:19
+   |
+LL | global_asm!("{}", const 0 as *mut u8);
+   |                   ^^^^^^------------
+   |                         |
+   |                         is a `*mut u8`
+   |
+   = help: `const` operands must be of an integer type
+
+error: invalid type for `const` operand
+  --> $DIR/invalid-const-operand.rs:26:20
+   |
+LL |         asm!("{}", const 0f32);
+   |                    ^^^^^^----
+   |                          |
+   |                          is an `f32`
+   |
+   = help: `const` operands must be of an integer type
+
+error: invalid type for `const` operand
+  --> $DIR/invalid-const-operand.rs:28:20
+   |
+LL |         asm!("{}", const 0 as *mut u8);
+   |                    ^^^^^^------------
+   |                          |
+   |                          is a `*mut u8`
+   |
+   = help: `const` operands must be of an integer type
+
+error: invalid type for `const` operand
+  --> $DIR/invalid-const-operand.rs:30:20
+   |
+LL |         asm!("{}", const &0);
+   |                    ^^^^^^--
+   |                          |
+   |                          is a `&i32`
+   |
+   = help: `const` operands must be of an integer type
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
diff --git a/tests/ui/asm/invalid-sym-operand.rs b/tests/ui/asm/invalid-sym-operand.rs
new file mode 100644
index 00000000000..2129c20b968
--- /dev/null
+++ b/tests/ui/asm/invalid-sym-operand.rs
@@ -0,0 +1,34 @@
+//@ needs-asm-support
+//@ ignore-nvptx64
+//@ ignore-spirv
+
+use std::arch::{asm, global_asm};
+
+// Sym operands must point to a function or static
+
+const C: i32 = 0;
+static S: i32 = 0;
+global_asm!("{}", sym S);
+global_asm!("{}", sym main);
+global_asm!("{}", sym C);
+//~^ ERROR invalid `sym` operand
+
+fn main() {
+    unsafe {
+        // Sym operands must point to a function or static
+
+        let x: u64 = 0;
+        const C: i32 = 0;
+        static S: i32 = 0;
+        asm!("{}", sym S);
+        asm!("{}", sym main);
+        asm!("{}", sym C);
+        //~^ ERROR invalid `sym` operand
+        asm!("{}", sym x);
+        //~^ ERROR invalid `sym` operand
+    }
+}
+
+unsafe fn generic<T>() {
+    asm!("{}", sym generic::<T>);
+}
diff --git a/tests/ui/asm/invalid-sym-operand.stderr b/tests/ui/asm/invalid-sym-operand.stderr
new file mode 100644
index 00000000000..f0e6a17c25f
--- /dev/null
+++ b/tests/ui/asm/invalid-sym-operand.stderr
@@ -0,0 +1,26 @@
+error: invalid `sym` operand
+  --> $DIR/invalid-sym-operand.rs:27:24
+   |
+LL |         asm!("{}", sym x);
+   |                        ^ is a local variable
+   |
+   = help: `sym` operands must refer to either a function or a static
+
+error: invalid `sym` operand
+  --> $DIR/invalid-sym-operand.rs:13:19
+   |
+LL | global_asm!("{}", sym C);
+   |                   ^^^^^ is an `i32`
+   |
+   = help: `sym` operands must refer to either a function or a static
+
+error: invalid `sym` operand
+  --> $DIR/invalid-sym-operand.rs:25:20
+   |
+LL |         asm!("{}", sym C);
+   |                    ^^^^^ is an `i32`
+   |
+   = help: `sym` operands must refer to either a function or a static
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/asm/parse-error.rs b/tests/ui/asm/parse-error.rs
index 9dec3a1c394..16ae0282864 100644
--- a/tests/ui/asm/parse-error.rs
+++ b/tests/ui/asm/parse-error.rs
@@ -146,5 +146,16 @@ global_asm!(format!("{{{}}}", 0), const FOO);
 //~^ ERROR asm template must be a string literal
 global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
 //~^ ERROR asm template must be a string literal
-global_asm!("{}", label {});
-//~^ ERROR expected operand, options, or additional template string
+
+global_asm!("{}", in(reg));
+//~^ ERROR the `in` operand cannot be used with `global_asm!`
+global_asm!("{}", out(reg));
+//~^ ERROR the `out` operand cannot be used with `global_asm!`
+global_asm!("{}", lateout(reg));
+//~^ ERROR the `lateout` operand cannot be used with `global_asm!`
+global_asm!("{}", inout(reg));
+//~^ ERROR the `inout` operand cannot be used with `global_asm!`
+global_asm!("{}", inlateout(reg));
+//~^ ERROR the `inlateout` operand cannot be used with `global_asm!`
+global_asm!("{}", label(reg));
+//~^ ERROR the `label` operand cannot be used with `global_asm!`
diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr
index e9ecd712bc3..f5f8d537d86 100644
--- a/tests/ui/asm/parse-error.stderr
+++ b/tests/ui/asm/parse-error.stderr
@@ -380,11 +380,41 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
    |
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: expected operand, options, or additional template string
-  --> $DIR/parse-error.rs:149:19
+error: the `in` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:150:19
+   |
+LL | global_asm!("{}", in(reg));
+   |                   ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `out` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:152:19
+   |
+LL | global_asm!("{}", out(reg));
+   |                   ^^^ the `out` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `lateout` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:154:19
+   |
+LL | global_asm!("{}", lateout(reg));
+   |                   ^^^^^^^ the `lateout` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `inout` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:156:19
+   |
+LL | global_asm!("{}", inout(reg));
+   |                   ^^^^^ the `inout` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `inlateout` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:158:19
+   |
+LL | global_asm!("{}", inlateout(reg));
+   |                   ^^^^^^^^^ the `inlateout` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `label` operand cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:160:19
    |
-LL | global_asm!("{}", label {});
-   |                   ^^^^^^^^ expected operand, options, or additional template string
+LL | global_asm!("{}", label(reg));
+   |                   ^^^^^ the `label` operand is not meaningful for global-scoped inline assembly, remove it
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:39:37
@@ -441,6 +471,6 @@ help: consider using `const` instead of `let`
 LL |     const bar: /* Type */ = 0;
    |     ~~~~~    ++++++++++++
 
-error: aborting due to 67 previous errors
+error: aborting due to 72 previous errors
 
 For more information about this error, try `rustc --explain E0435`.
diff --git a/tests/ui/asm/type-check-1.rs b/tests/ui/asm/type-check-1.rs
index b0f1362f543..22669dce280 100644
--- a/tests/ui/asm/type-check-1.rs
+++ b/tests/ui/asm/type-check-1.rs
@@ -28,51 +28,5 @@ fn main() {
         asm!("{}", inout(reg) v[..]);
         //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time
         //~| ERROR cannot use value of type `[u64]` for inline assembly
-
-        // Constants must be... constant
-
-        let x = 0;
-        const fn const_foo(x: i32) -> i32 {
-            x
-        }
-        const fn const_bar<T>(x: T) -> T {
-            x
-        }
-        asm!("{}", const x);
-        //~^ ERROR attempt to use a non-constant value in a constant
-        asm!("{}", const const_foo(0));
-        asm!("{}", const const_foo(x));
-        //~^ ERROR attempt to use a non-constant value in a constant
-        asm!("{}", const const_bar(0));
-        asm!("{}", const const_bar(x));
-        //~^ ERROR attempt to use a non-constant value in a constant
-        asm!("{}", sym x);
-        //~^ ERROR invalid `sym` operand
-
-        // Const operands must be integers and must be constants.
-
-        asm!("{}", const 0);
-        asm!("{}", const 0i32);
-        asm!("{}", const 0i128);
-        asm!("{}", const 0f32);
-        //~^ ERROR mismatched types
-        asm!("{}", const 0 as *mut u8);
-        //~^ ERROR mismatched types
-        asm!("{}", const &0);
-        //~^ ERROR mismatched types
     }
 }
-
-unsafe fn generic<T>() {
-    asm!("{}", sym generic::<T>);
-}
-
-// Const operands must be integers and must be constants.
-
-global_asm!("{}", const 0);
-global_asm!("{}", const 0i32);
-global_asm!("{}", const 0i128);
-global_asm!("{}", const 0f32);
-//~^ ERROR mismatched types
-global_asm!("{}", const 0 as *mut u8);
-//~^ ERROR mismatched types
diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr
index 18526232118..d47e6ae1d2a 100644
--- a/tests/ui/asm/type-check-1.stderr
+++ b/tests/ui/asm/type-check-1.stderr
@@ -1,44 +1,3 @@
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/type-check-1.rs:41:26
-   |
-LL |         asm!("{}", const x);
-   |                          ^ non-constant value
-   |
-help: consider using `const` instead of `let`
-   |
-LL |         const x: /* Type */ = 0;
-   |         ~~~~~  ++++++++++++
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/type-check-1.rs:44:36
-   |
-LL |         asm!("{}", const const_foo(x));
-   |                                    ^ non-constant value
-   |
-help: consider using `const` instead of `let`
-   |
-LL |         const x: /* Type */ = 0;
-   |         ~~~~~  ++++++++++++
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/type-check-1.rs:47:36
-   |
-LL |         asm!("{}", const const_bar(x));
-   |                                    ^ non-constant value
-   |
-help: consider using `const` instead of `let`
-   |
-LL |         const x: /* Type */ = 0;
-   |         ~~~~~  ++++++++++++
-
-error: invalid `sym` operand
-  --> $DIR/type-check-1.rs:49:24
-   |
-LL |         asm!("{}", sym x);
-   |                        ^ is a local variable
-   |
-   = help: `sym` operands must refer to either a function or a static
-
 error: invalid asm output
   --> $DIR/type-check-1.rs:14:29
    |
@@ -102,49 +61,6 @@ LL |         asm!("{}", inout(reg) v[..]);
    |
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
-error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:57:26
-   |
-LL |         asm!("{}", const 0f32);
-   |                          ^^^^ expected integer, found `f32`
-
-error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:59:26
-   |
-LL |         asm!("{}", const 0 as *mut u8);
-   |                          ^^^^^^^^^^^^ expected integer, found `*mut u8`
-   |
-   = note:     expected type `{integer}`
-           found raw pointer `*mut u8`
-
-error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:61:26
-   |
-LL |         asm!("{}", const &0);
-   |                          ^^ expected integer, found `&{integer}`
-   |
-help: consider removing the borrow
-   |
-LL -         asm!("{}", const &0);
-LL +         asm!("{}", const 0);
-   |
-
-error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:75:25
-   |
-LL | global_asm!("{}", const 0f32);
-   |                         ^^^^ expected integer, found `f32`
-
-error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:77:25
-   |
-LL | global_asm!("{}", const 0 as *mut u8);
-   |                         ^^^^^^^^^^^^ expected integer, found `*mut u8`
-   |
-   = note:     expected type `{integer}`
-           found raw pointer `*mut u8`
-
-error: aborting due to 17 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0277, E0308, E0435.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/asm/x86_64/type-check-2.rs b/tests/ui/asm/x86_64/type-check-2.rs
index 4b5d59fdbc7..ff811961462 100644
--- a/tests/ui/asm/x86_64/type-check-2.rs
+++ b/tests/ui/asm/x86_64/type-check-2.rs
@@ -27,17 +27,6 @@ fn main() {
         asm!("{}", out(reg) v[0]);
         asm!("{}", inout(reg) v[0]);
 
-        // Sym operands must point to a function or static
-
-        const C: i32 = 0;
-        static S: i32 = 0;
-        asm!("{}", sym S);
-        asm!("{}", sym main);
-        asm!("{}", sym C);
-        //~^ ERROR invalid `sym` operand
-        asm!("{}", sym x);
-        //~^ ERROR invalid `sym` operand
-
         // Register operands must be Copy
 
         asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
@@ -79,12 +68,3 @@ fn main() {
         asm!("{}", in(reg) u);
     }
 }
-
-// Sym operands must point to a function or static
-
-const C: i32 = 0;
-static S: i32 = 0;
-global_asm!("{}", sym S);
-global_asm!("{}", sym main);
-global_asm!("{}", sym C);
-//~^ ERROR invalid `sym` operand
diff --git a/tests/ui/asm/x86_64/type-check-2.stderr b/tests/ui/asm/x86_64/type-check-2.stderr
index 6ae118b16e7..c72e695aefb 100644
--- a/tests/ui/asm/x86_64/type-check-2.stderr
+++ b/tests/ui/asm/x86_64/type-check-2.stderr
@@ -1,37 +1,13 @@
-error: invalid `sym` operand
-  --> $DIR/type-check-2.rs:38:24
-   |
-LL |         asm!("{}", sym x);
-   |                        ^ is a local variable
-   |
-   = help: `sym` operands must refer to either a function or a static
-
-error: invalid `sym` operand
-  --> $DIR/type-check-2.rs:89:19
-   |
-LL | global_asm!("{}", sym C);
-   |                   ^^^^^ is an `i32`
-   |
-   = help: `sym` operands must refer to either a function or a static
-
-error: invalid `sym` operand
-  --> $DIR/type-check-2.rs:36:20
-   |
-LL |         asm!("{}", sym C);
-   |                    ^^^^^ is an `i32`
-   |
-   = help: `sym` operands must refer to either a function or a static
-
 error: arguments for inline assembly must be copyable
-  --> $DIR/type-check-2.rs:43:32
+  --> $DIR/type-check-2.rs:32:32
    |
 LL |         asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `SimdNonCopy` does not implement the Copy trait
 
-error: cannot use value of type `{closure@$DIR/type-check-2.rs:55:28: 55:36}` for inline assembly
-  --> $DIR/type-check-2.rs:55:28
+error: cannot use value of type `{closure@$DIR/type-check-2.rs:44:28: 44:36}` for inline assembly
+  --> $DIR/type-check-2.rs:44:28
    |
 LL |         asm!("{}", in(reg) |x: i32| x);
    |                            ^^^^^^^^^^
@@ -39,7 +15,7 @@ LL |         asm!("{}", in(reg) |x: i32| x);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `Vec<i32>` for inline assembly
-  --> $DIR/type-check-2.rs:57:28
+  --> $DIR/type-check-2.rs:46:28
    |
 LL |         asm!("{}", in(reg) vec![0]);
    |                            ^^^^^^^
@@ -48,7 +24,7 @@ LL |         asm!("{}", in(reg) vec![0]);
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: cannot use value of type `(i32, i32, i32)` for inline assembly
-  --> $DIR/type-check-2.rs:59:28
+  --> $DIR/type-check-2.rs:48:28
    |
 LL |         asm!("{}", in(reg) (1, 2, 3));
    |                            ^^^^^^^^^
@@ -56,7 +32,7 @@ LL |         asm!("{}", in(reg) (1, 2, 3));
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `[i32; 3]` for inline assembly
-  --> $DIR/type-check-2.rs:61:28
+  --> $DIR/type-check-2.rs:50:28
    |
 LL |         asm!("{}", in(reg) [1, 2, 3]);
    |                            ^^^^^^^^^
@@ -64,7 +40,7 @@ LL |         asm!("{}", in(reg) [1, 2, 3]);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `fn() {main}` for inline assembly
-  --> $DIR/type-check-2.rs:69:31
+  --> $DIR/type-check-2.rs:58:31
    |
 LL |         asm!("{}", inout(reg) f);
    |                               ^
@@ -72,7 +48,7 @@ LL |         asm!("{}", inout(reg) f);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error: cannot use value of type `&mut i32` for inline assembly
-  --> $DIR/type-check-2.rs:72:31
+  --> $DIR/type-check-2.rs:61:31
    |
 LL |         asm!("{}", inout(reg) r);
    |                               ^
@@ -121,7 +97,7 @@ help: consider changing this to be mutable
 LL |         let mut v: Vec<u64> = vec![0, 1, 2];
    |             +++
 
-error: aborting due to 13 previous errors
+error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0381, E0596.
 For more information about an error, try `rustc --explain E0381`.
diff --git a/tests/ui/associated-type-bounds/name-same-as-generic-type-issue-128249.rs b/tests/ui/associated-type-bounds/name-same-as-generic-type-issue-128249.rs
new file mode 100644
index 00000000000..f5f8fa51e37
--- /dev/null
+++ b/tests/ui/associated-type-bounds/name-same-as-generic-type-issue-128249.rs
@@ -0,0 +1,15 @@
+trait Trait<Type> {
+    type Type;
+
+    fn one(&self, val:  impl Trait<Type: Default>);
+    //~^ ERROR trait takes 1 generic argument but 0 generic arguments were supplied
+
+    fn two<T: Trait<Type: Default>>(&self) -> T;
+    //~^ ERROR trait takes 1 generic argument but 0 generic arguments were supplied
+
+    fn three<T>(&self) -> T where
+        T: Trait<Type: Default>,;
+    //~^ ERROR trait takes 1 generic argument but 0 generic arguments were supplied
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/name-same-as-generic-type-issue-128249.stderr b/tests/ui/associated-type-bounds/name-same-as-generic-type-issue-128249.stderr
new file mode 100644
index 00000000000..06ab06003a1
--- /dev/null
+++ b/tests/ui/associated-type-bounds/name-same-as-generic-type-issue-128249.stderr
@@ -0,0 +1,51 @@
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/name-same-as-generic-type-issue-128249.rs:4:30
+   |
+LL |     fn one(&self, val:  impl Trait<Type: Default>);
+   |                              ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `Type`
+  --> $DIR/name-same-as-generic-type-issue-128249.rs:1:7
+   |
+LL | trait Trait<Type> {
+   |       ^^^^^ ----
+help: add missing generic argument
+   |
+LL |     fn one(&self, val:  impl Trait<Type, Type: Default>);
+   |                                    +++++
+
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/name-same-as-generic-type-issue-128249.rs:7:15
+   |
+LL |     fn two<T: Trait<Type: Default>>(&self) -> T;
+   |               ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `Type`
+  --> $DIR/name-same-as-generic-type-issue-128249.rs:1:7
+   |
+LL | trait Trait<Type> {
+   |       ^^^^^ ----
+help: add missing generic argument
+   |
+LL |     fn two<T: Trait<Type, Type: Default>>(&self) -> T;
+   |                     +++++
+
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/name-same-as-generic-type-issue-128249.rs:11:12
+   |
+LL |         T: Trait<Type: Default>,;
+   |            ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `Type`
+  --> $DIR/name-same-as-generic-type-issue-128249.rs:1:7
+   |
+LL | trait Trait<Type> {
+   |       ^^^^^ ----
+help: add missing generic argument
+   |
+LL |         T: Trait<Type, Type: Default>,;
+   |                  +++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/async-await/async-closures/fn-exception-target-features.rs b/tests/ui/async-await/async-closures/fn-exception-target-features.rs
new file mode 100644
index 00000000000..de62fc8bf7e
--- /dev/null
+++ b/tests/ui/async-await/async-closures/fn-exception-target-features.rs
@@ -0,0 +1,17 @@
+//@ edition: 2021
+//@ only-x86_64
+
+#![feature(async_closure, target_feature_11)]
+// `target_feature_11` just to test safe functions w/ target features.
+
+use std::pin::Pin;
+use std::future::Future;
+
+#[target_feature(enable = "sse2")]
+fn target_feature()  -> Pin<Box<dyn Future<Output = ()> + 'static>> { todo!() }
+
+fn test(f: impl async Fn()) {}
+
+fn main() {
+    test(target_feature); //~ ERROR the trait bound
+}
diff --git a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr
new file mode 100644
index 00000000000..396167f4070
--- /dev/null
+++ b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}: AsyncFn<()>` is not satisfied
+  --> $DIR/fn-exception-target-features.rs:16:10
+   |
+LL |     test(target_feature);
+   |     ---- ^^^^^^^^^^^^^^ the trait `AsyncFn<()>` is not implemented for fn item `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `test`
+  --> $DIR/fn-exception-target-features.rs:13:17
+   |
+LL | fn test(f: impl async Fn()) {}
+   |                 ^^^^^^^^^^ required by this bound in `test`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-closures/fn-exception.rs b/tests/ui/async-await/async-closures/fn-exception.rs
new file mode 100644
index 00000000000..0e06ebf48a4
--- /dev/null
+++ b/tests/ui/async-await/async-closures/fn-exception.rs
@@ -0,0 +1,21 @@
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+use std::pin::Pin;
+use std::future::Future;
+
+unsafe extern "Rust" {
+    pub unsafe fn unsafety() -> Pin<Box<dyn Future<Output = ()> + 'static>>;
+}
+
+unsafe extern "C" {
+    pub safe fn abi() -> Pin<Box<dyn Future<Output = ()> + 'static>>;
+}
+
+fn test(f: impl async Fn()) {}
+
+fn main() {
+    test(unsafety); //~ ERROR the trait bound
+    test(abi); //~ ERROR the trait bound
+}
diff --git a/tests/ui/async-await/async-closures/fn-exception.stderr b/tests/ui/async-await/async-closures/fn-exception.stderr
new file mode 100644
index 00000000000..bacd079af0f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/fn-exception.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the trait bound `unsafe fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {unsafety}: AsyncFn<()>` is not satisfied
+  --> $DIR/fn-exception.rs:19:10
+   |
+LL |     test(unsafety);
+   |     ---- ^^^^^^^^ the trait `AsyncFn<()>` is not implemented for fn item `unsafe fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {unsafety}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `test`
+  --> $DIR/fn-exception.rs:16:17
+   |
+LL | fn test(f: impl async Fn()) {}
+   |                 ^^^^^^^^^^ required by this bound in `test`
+
+error[E0277]: the trait bound `extern "C" fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {abi}: AsyncFn<()>` is not satisfied
+  --> $DIR/fn-exception.rs:20:10
+   |
+LL |     test(abi);
+   |     ---- ^^^ the trait `AsyncFn<()>` is not implemented for fn item `extern "C" fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {abi}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `test`
+  --> $DIR/fn-exception.rs:16:17
+   |
+LL | fn test(f: impl async Fn()) {}
+   |                 ^^^^^^^^^^ required by this bound in `test`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-closures/non-copy-arg-does-not-force-inner-move.rs b/tests/ui/async-await/async-closures/non-copy-arg-does-not-force-inner-move.rs
new file mode 100644
index 00000000000..cd9d98d0799
--- /dev/null
+++ b/tests/ui/async-await/async-closures/non-copy-arg-does-not-force-inner-move.rs
@@ -0,0 +1,17 @@
+//@ aux-build:block-on.rs
+//@ edition:2021
+//@ build-pass
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+fn wrapper(f: impl Fn(String)) -> impl async Fn(String) {
+    async move |s| f(s)
+}
+
+fn main() {
+    block_on::block_on(async {
+        wrapper(|who| println!("Hello, {who}!"))(String::from("world")).await;
+    });
+}
diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs
index d3d1284982a..a5c81a92998 100644
--- a/tests/ui/async-await/in-trait/generics-mismatch.rs
+++ b/tests/ui/async-await/in-trait/generics-mismatch.rs
@@ -6,7 +6,7 @@ trait Foo {
 
 impl Foo for () {
     async fn foo<const N: usize>() {}
-    //~^ ERROR: method `foo` has an incompatible generic parameter for trait `Foo` [E0053]
+    //~^ ERROR: associated function `foo` has an incompatible generic parameter for trait `Foo` [E0053]
 }
 
 fn main() {}
diff --git a/tests/ui/async-await/in-trait/generics-mismatch.stderr b/tests/ui/async-await/in-trait/generics-mismatch.stderr
index c0357dc7f3e..cb0f95e8d09 100644
--- a/tests/ui/async-await/in-trait/generics-mismatch.stderr
+++ b/tests/ui/async-await/in-trait/generics-mismatch.stderr
@@ -1,4 +1,4 @@
-error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo`
+error[E0053]: associated function `foo` has an incompatible generic parameter for trait `Foo`
   --> $DIR/generics-mismatch.rs:8:18
    |
 LL | trait Foo {
diff --git a/tests/ui/attributes/check-builtin-attr-ice.rs b/tests/ui/attributes/check-builtin-attr-ice.rs
new file mode 100644
index 00000000000..9ef5890601f
--- /dev/null
+++ b/tests/ui/attributes/check-builtin-attr-ice.rs
@@ -0,0 +1,58 @@
+//! Regression test for #128622.
+//!
+//! PR #128581 introduced an assertion that all builtin attributes are actually checked via
+//! `CheckAttrVisitor` and aren't accidentally usable on completely unrelated HIR nodes.
+//! Unfortunately, the check had correctness problems.
+//!
+//! The match on attribute path segments looked like
+//!
+//! ```rs,ignore
+//! [sym::should_panic] => /* check is implemented */
+//! match BUILTIN_ATTRIBUTE_MAP.get(name) {
+//!     // checked below
+//!     Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
+//!     Some(_) => {
+//!         if !name.as_str().starts_with("rustc_") {
+//!             span_bug!(
+//!                 attr.span,
+//!                 "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
+//!             )
+//!         }
+//!     }
+//!     None => (),
+//! }
+//! ```
+//!
+//! However, it failed to account for edge cases such as an attribute whose:
+//!
+//! 1. path segments *starts* with a builtin attribute such as `should_panic`
+//! 2. which does not start with `rustc_`, and
+//! 3. is also an `AttributeType::Normal` attribute upon registration with the builtin attribute map
+//!
+//! These conditions when all satisfied cause the span bug to be issued for e.g.
+//! `#[should_panic::skip]` because the `[sym::should_panic]` arm is not matched (since it's
+//! `[sym::should_panic, sym::skip]`).
+//!
+//! This test checks that the span bug is not fired for such cases.
+//!
+//! issue: rust-lang/rust#128622
+
+// Notably, `should_panic` is a `AttributeType::Normal` attribute that is checked separately.
+
+struct Foo {
+    #[should_panic::skip]
+    //~^ ERROR failed to resolve
+    pub field: u8,
+
+    #[should_panic::a::b::c]
+    //~^ ERROR failed to resolve
+    pub field2: u8,
+}
+
+fn foo() {}
+
+fn main() {
+    #[deny::skip]
+    //~^ ERROR failed to resolve
+    foo();
+}
diff --git a/tests/ui/attributes/check-builtin-attr-ice.stderr b/tests/ui/attributes/check-builtin-attr-ice.stderr
new file mode 100644
index 00000000000..5a27da565a8
--- /dev/null
+++ b/tests/ui/attributes/check-builtin-attr-ice.stderr
@@ -0,0 +1,21 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `should_panic`
+  --> $DIR/check-builtin-attr-ice.rs:43:7
+   |
+LL |     #[should_panic::skip]
+   |       ^^^^^^^^^^^^ use of undeclared crate or module `should_panic`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `should_panic`
+  --> $DIR/check-builtin-attr-ice.rs:47:7
+   |
+LL |     #[should_panic::a::b::c]
+   |       ^^^^^^^^^^^^ use of undeclared crate or module `should_panic`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `deny`
+  --> $DIR/check-builtin-attr-ice.rs:55:7
+   |
+LL |     #[deny::skip]
+   |       ^^^^ use of undeclared crate or module `deny`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/attributes/check-cfg_attr-ice.rs b/tests/ui/attributes/check-cfg_attr-ice.rs
new file mode 100644
index 00000000000..5bf8baab141
--- /dev/null
+++ b/tests/ui/attributes/check-cfg_attr-ice.rs
@@ -0,0 +1,68 @@
+//! I missed a `cfg_attr` match in #128581, it should have had the same treatment as `cfg`. If
+//! an invalid attribute starting with `cfg_attr` is passed, then it would trigger an ICE because
+//! it was not considered "checked" (e.g. `#[cfg_attr::skip]` or `#[cfg_attr::no_such_thing]`).
+//!
+//! This test is not exhaustive, there's too many possible positions to check, instead it just does
+//! a basic smoke test in a few select positions to make sure we don't ICE for e.g.
+//! `#[cfg_attr::no_such_thing]`.
+//!
+//! issue: rust-lang/rust#128716
+#![crate_type = "lib"]
+
+#[cfg_attr::no_such_thing]
+//~^ ERROR failed to resolve
+mod we_are_no_strangers_to_love {}
+
+#[cfg_attr::no_such_thing]
+//~^ ERROR failed to resolve
+struct YouKnowTheRules {
+    #[cfg_attr::no_such_thing]
+    //~^ ERROR failed to resolve
+    and_so_do_i: u8,
+}
+
+#[cfg_attr::no_such_thing]
+//~^ ERROR failed to resolve
+fn a_full_commitment() {
+    #[cfg_attr::no_such_thing]
+    //~^ ERROR failed to resolve
+    let is_what_i_am_thinking_of = ();
+}
+
+#[cfg_attr::no_such_thing]
+//~^ ERROR failed to resolve
+union AnyOtherGuy {
+    owo: ()
+}
+struct This;
+
+#[cfg_attr(FALSE, doc = "you wouldn't get this")]
+impl From<AnyOtherGuy> for This {
+    #[cfg_attr::no_such_thing]
+    //~^ ERROR failed to resolve
+    fn from(#[cfg_attr::no_such_thing] any_other_guy: AnyOtherGuy) -> This {
+        //~^ ERROR failed to resolve
+        #[cfg_attr::no_such_thing]
+        //~^ ERROR attributes on expressions are experimental
+        //~| ERROR failed to resolve
+        unreachable!()
+    }
+}
+
+#[cfg_attr::no_such_thing]
+//~^ ERROR failed to resolve
+enum NeverGonna {
+    #[cfg_attr::no_such_thing]
+    //~^ ERROR failed to resolve
+    GiveYouUp(#[cfg_attr::no_such_thing] u8),
+    //~^ ERROR failed to resolve
+    LetYouDown {
+        #![cfg_attr::no_such_thing]
+        //~^ ERROR an inner attribute is not permitted in this context
+        never_gonna: (),
+        round_around: (),
+        #[cfg_attr::no_such_thing]
+        //~^ ERROR failed to resolve
+        and_desert_you: (),
+    },
+}
diff --git a/tests/ui/attributes/check-cfg_attr-ice.stderr b/tests/ui/attributes/check-cfg_attr-ice.stderr
new file mode 100644
index 00000000000..dbdf32597f7
--- /dev/null
+++ b/tests/ui/attributes/check-cfg_attr-ice.stderr
@@ -0,0 +1,101 @@
+error: an inner attribute is not permitted in this context
+  --> $DIR/check-cfg_attr-ice.rs:60:9
+   |
+LL |         #![cfg_attr::no_such_thing]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+   = note: outer attributes, like `#[test]`, annotate the item following them
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/check-cfg_attr-ice.rs:45:9
+   |
+LL |         #[cfg_attr::no_such_thing]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:52:3
+   |
+LL | #[cfg_attr::no_such_thing]
+   |   ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:55:7
+   |
+LL |     #[cfg_attr::no_such_thing]
+   |       ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:57:17
+   |
+LL |     GiveYouUp(#[cfg_attr::no_such_thing] u8),
+   |                 ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:64:11
+   |
+LL |         #[cfg_attr::no_such_thing]
+   |           ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:41:7
+   |
+LL |     #[cfg_attr::no_such_thing]
+   |       ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:43:15
+   |
+LL |     fn from(#[cfg_attr::no_such_thing] any_other_guy: AnyOtherGuy) -> This {
+   |               ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:45:11
+   |
+LL |         #[cfg_attr::no_such_thing]
+   |           ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:32:3
+   |
+LL | #[cfg_attr::no_such_thing]
+   |   ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:24:3
+   |
+LL | #[cfg_attr::no_such_thing]
+   |   ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:27:7
+   |
+LL |     #[cfg_attr::no_such_thing]
+   |       ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:16:3
+   |
+LL | #[cfg_attr::no_such_thing]
+   |   ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:19:7
+   |
+LL |     #[cfg_attr::no_such_thing]
+   |       ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `cfg_attr`
+  --> $DIR/check-cfg_attr-ice.rs:12:3
+   |
+LL | #[cfg_attr::no_such_thing]
+   |   ^^^^^^^^ use of undeclared crate or module `cfg_attr`
+
+error: aborting due to 15 previous errors
+
+Some errors have detailed explanations: E0433, E0658.
+For more information about an error, try `rustc --explain E0433`.
diff --git a/tests/ui/attributes/no-sanitize.rs b/tests/ui/attributes/no-sanitize.rs
new file mode 100644
index 00000000000..82b7a22d570
--- /dev/null
+++ b/tests/ui/attributes/no-sanitize.rs
@@ -0,0 +1,34 @@
+#![feature(no_sanitize)]
+#![feature(stmt_expr_attributes)]
+#![deny(unused_attributes)]
+#![allow(dead_code)]
+
+fn invalid() {
+    #[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
+    {
+        1
+    };
+}
+
+#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
+type InvalidTy = ();
+
+#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
+mod invalid_module {}
+
+fn main() {
+    let _ = #[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
+    (|| 1);
+}
+
+#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
+struct F;
+
+#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
+impl F {
+    #[no_sanitize(memory)]
+    fn valid(&self) {}
+}
+
+#[no_sanitize(memory)]
+fn valid() {}
diff --git a/tests/ui/attributes/no-sanitize.stderr b/tests/ui/attributes/no-sanitize.stderr
new file mode 100644
index 00000000000..f742ba0beed
--- /dev/null
+++ b/tests/ui/attributes/no-sanitize.stderr
@@ -0,0 +1,55 @@
+error: attribute should be applied to a function definition
+  --> $DIR/no-sanitize.rs:7:5
+   |
+LL |       #[no_sanitize(memory)]
+   |       ^^^^^^^^^^^^^^^^^^^^^^
+LL | /     {
+LL | |         1
+LL | |     };
+   | |_____- not a function definition
+
+error: attribute should be applied to a function definition
+  --> $DIR/no-sanitize.rs:13:1
+   |
+LL | #[no_sanitize(memory)]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | type InvalidTy = ();
+   | -------------------- not a function definition
+
+error: attribute should be applied to a function definition
+  --> $DIR/no-sanitize.rs:16:1
+   |
+LL | #[no_sanitize(memory)]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | mod invalid_module {}
+   | --------------------- not a function definition
+
+error: attribute should be applied to a function definition
+  --> $DIR/no-sanitize.rs:20:13
+   |
+LL |     let _ = #[no_sanitize(memory)]
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+LL |     (|| 1);
+   |     ------ not a function definition
+
+error: attribute should be applied to a function definition
+  --> $DIR/no-sanitize.rs:24:1
+   |
+LL | #[no_sanitize(memory)]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | struct F;
+   | --------- not a function definition
+
+error: attribute should be applied to a function definition
+  --> $DIR/no-sanitize.rs:27:1
+   |
+LL |   #[no_sanitize(memory)]
+   |   ^^^^^^^^^^^^^^^^^^^^^^
+LL | / impl F {
+LL | |     #[no_sanitize(memory)]
+LL | |     fn valid(&self) {}
+LL | | }
+   | |_- not a function definition
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/cast/dyn-tails-need-normalization.rs b/tests/ui/cast/dyn-tails-need-normalization.rs
new file mode 100644
index 00000000000..719e0e89243
--- /dev/null
+++ b/tests/ui/cast/dyn-tails-need-normalization.rs
@@ -0,0 +1,21 @@
+//@ check-pass
+
+trait Trait {
+    type Associated;
+}
+
+impl Trait for i32 {
+    type Associated = i64;
+}
+
+trait Generic<T> {}
+
+type TraitObject = dyn Generic<<i32 as Trait>::Associated>;
+
+struct Wrap(TraitObject);
+
+fn cast(x: *mut TraitObject) {
+    x as *mut Wrap;
+}
+
+fn main() {}
diff --git a/tests/ui/cfg/disallowed-cli-cfgs-allow.rs b/tests/ui/cfg/disallowed-cli-cfgs-allow.rs
new file mode 100644
index 00000000000..0a9b07429d5
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs-allow.rs
@@ -0,0 +1,4 @@
+//@ check-pass
+//@ compile-flags: --cfg unix -Aexplicit_builtin_cfgs_in_flags
+
+fn main() {}
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.debug_assertions_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.debug_assertions_.stderr
new file mode 100644
index 00000000000..ec3e15b85c7
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.debug_assertions_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg debug_assertions` flag
+   |
+   = note: config `debug_assertions` is only supposed to be controlled by `-C debug-assertions`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.overflow_checks_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.overflow_checks_.stderr
new file mode 100644
index 00000000000..ba8ed3f2e65
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.overflow_checks_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg overflow_checks` flag
+   |
+   = note: config `overflow_checks` is only supposed to be controlled by `-C overflow-checks`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.panic_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.panic_.stderr
new file mode 100644
index 00000000000..5b375694b13
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.panic_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg panic="abort"` flag
+   |
+   = note: config `panic` is only supposed to be controlled by `-C panic`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.proc_macro_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.proc_macro_.stderr
new file mode 100644
index 00000000000..c2e29908857
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.proc_macro_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg proc_macro` flag
+   |
+   = note: config `proc_macro` is only supposed to be controlled by `--crate-type proc-macro`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.relocation_model_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.relocation_model_.stderr
new file mode 100644
index 00000000000..65ada551cba
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.relocation_model_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg relocation_model="a"` flag
+   |
+   = note: config `relocation_model` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.rs b/tests/ui/cfg/disallowed-cli-cfgs.rs
new file mode 100644
index 00000000000..714c01f4bc6
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.rs
@@ -0,0 +1,35 @@
+//@ check-fail
+//@ revisions: overflow_checks_ debug_assertions_ ub_checks_ sanitize_
+//@ revisions: sanitizer_cfi_generalize_pointers_ sanitizer_cfi_normalize_integers_
+//@ revisions: proc_macro_ panic_ target_feature_ unix_ windows_ target_abi_
+//@ revisions: target_arch_ target_endian_ target_env_ target_family_ target_os_
+//@ revisions: target_pointer_width_ target_vendor_ target_has_atomic_
+//@ revisions: target_has_atomic_equal_alignment_ target_has_atomic_load_store_
+//@ revisions: target_thread_local_ relocation_model_
+
+//@ [overflow_checks_]compile-flags: --cfg overflow_checks
+//@ [debug_assertions_]compile-flags: --cfg debug_assertions
+//@ [ub_checks_]compile-flags: --cfg ub_checks
+//@ [sanitize_]compile-flags: --cfg sanitize="cfi"
+//@ [sanitizer_cfi_generalize_pointers_]compile-flags: --cfg sanitizer_cfi_generalize_pointers
+//@ [sanitizer_cfi_normalize_integers_]compile-flags: --cfg sanitizer_cfi_normalize_integers
+//@ [proc_macro_]compile-flags: --cfg proc_macro
+//@ [panic_]compile-flags: --cfg panic="abort"
+//@ [target_feature_]compile-flags: --cfg target_feature="sse3"
+//@ [unix_]compile-flags: --cfg unix
+//@ [windows_]compile-flags: --cfg windows
+//@ [target_abi_]compile-flags: --cfg target_abi="gnu"
+//@ [target_arch_]compile-flags: --cfg target_arch="arm"
+//@ [target_endian_]compile-flags: --cfg target_endian="little"
+//@ [target_env_]compile-flags: --cfg target_env
+//@ [target_family_]compile-flags: --cfg target_family="unix"
+//@ [target_os_]compile-flags: --cfg target_os="linux"
+//@ [target_pointer_width_]compile-flags: --cfg target_pointer_width="32"
+//@ [target_vendor_]compile-flags: --cfg target_vendor
+//@ [target_has_atomic_]compile-flags: --cfg target_has_atomic="32"
+//@ [target_has_atomic_equal_alignment_]compile-flags: --cfg target_has_atomic_equal_alignment="32"
+//@ [target_has_atomic_load_store_]compile-flags: --cfg target_has_atomic_load_store="32"
+//@ [target_thread_local_]compile-flags: --cfg target_thread_local
+//@ [relocation_model_]compile-flags: --cfg relocation_model="a"
+
+fn main() {}
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.sanitize_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.sanitize_.stderr
new file mode 100644
index 00000000000..b1f3b19dd86
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.sanitize_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg sanitize="cfi"` flag
+   |
+   = note: config `sanitize` is only supposed to be controlled by `-Z sanitizer`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.sanitizer_cfi_generalize_pointers_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.sanitizer_cfi_generalize_pointers_.stderr
new file mode 100644
index 00000000000..49106f99b6b
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.sanitizer_cfi_generalize_pointers_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg sanitizer_cfi_generalize_pointers` flag
+   |
+   = note: config `sanitizer_cfi_generalize_pointers` is only supposed to be controlled by `-Z sanitizer=cfi`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.sanitizer_cfi_normalize_integers_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.sanitizer_cfi_normalize_integers_.stderr
new file mode 100644
index 00000000000..f9bb9e76297
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.sanitizer_cfi_normalize_integers_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg sanitizer_cfi_normalize_integers` flag
+   |
+   = note: config `sanitizer_cfi_normalize_integers` is only supposed to be controlled by `-Z sanitizer=cfi`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_abi_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_abi_.stderr
new file mode 100644
index 00000000000..f5c09110ce8
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_abi_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_abi="gnu"` flag
+   |
+   = note: config `target_abi` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_arch_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_arch_.stderr
new file mode 100644
index 00000000000..7f616e75d4e
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_arch_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_arch="arm"` flag
+   |
+   = note: config `target_arch` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_endian_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_endian_.stderr
new file mode 100644
index 00000000000..755f3708d67
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_endian_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_endian="little"` flag
+   |
+   = note: config `target_endian` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_env_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_env_.stderr
new file mode 100644
index 00000000000..ccd027dbebe
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_env_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_env` flag
+   |
+   = note: config `target_env` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_family_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_family_.stderr
new file mode 100644
index 00000000000..e376e4e16a1
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_family_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_family="unix"` flag
+   |
+   = note: config `target_family` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_feature_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_feature_.stderr
new file mode 100644
index 00000000000..457cca6b885
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_feature_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_feature="sse3"` flag
+   |
+   = note: config `target_feature` is only supposed to be controlled by `-C target-feature`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_.stderr
new file mode 100644
index 00000000000..160741198ad
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_has_atomic="32"` flag
+   |
+   = note: config `target_has_atomic` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_equal_alignment_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_equal_alignment_.stderr
new file mode 100644
index 00000000000..096490a03f6
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_equal_alignment_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_has_atomic_equal_alignment="32"` flag
+   |
+   = note: config `target_has_atomic_equal_alignment` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_load_store_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_load_store_.stderr
new file mode 100644
index 00000000000..5253987cb12
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_has_atomic_load_store_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_has_atomic_load_store="32"` flag
+   |
+   = note: config `target_has_atomic_load_store` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_os_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_os_.stderr
new file mode 100644
index 00000000000..ba2c967bfa1
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_os_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_os="linux"` flag
+   |
+   = note: config `target_os` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_pointer_width_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_pointer_width_.stderr
new file mode 100644
index 00000000000..983313bc517
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_pointer_width_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_pointer_width="32"` flag
+   |
+   = note: config `target_pointer_width` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_thread_local_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_thread_local_.stderr
new file mode 100644
index 00000000000..4f66ea17ee4
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_thread_local_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_thread_local` flag
+   |
+   = note: config `target_thread_local` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_vendor_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_vendor_.stderr
new file mode 100644
index 00000000000..e8f32598445
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.target_vendor_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg target_vendor` flag
+   |
+   = note: config `target_vendor` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.test_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.test_.stderr
new file mode 100644
index 00000000000..96b5beb0210
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.test_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg test` flag
+   |
+   = note: config `test` is only supposed to be controlled by `--test`
+   = note: see <https://github.com/rust-lang/rust/issues/xxxxx> for more information
+   = note: `#[deny(unexpected_builtin_cfgs)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.ub_checks_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.ub_checks_.stderr
new file mode 100644
index 00000000000..e61e5ac69d5
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.ub_checks_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg ub_checks` flag
+   |
+   = note: config `ub_checks` is only supposed to be controlled by `-Z ub-checks`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.unix_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.unix_.stderr
new file mode 100644
index 00000000000..f3c6bb0ef1b
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.unix_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg unix` flag
+   |
+   = note: config `unix` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.windows_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.windows_.stderr
new file mode 100644
index 00000000000..171a3f95bbd
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.windows_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg windows` flag
+   |
+   = note: config `windows` is only supposed to be controlled by `--target`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 57cbe173c78..520cffc4b02 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra`
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 199 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 201 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 00abb5f5e5c..d780e04e729 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs b/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs
index 52ed008137f..74f37b514e4 100644
--- a/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs
@@ -1,10 +1,9 @@
 // Test precise capture of a multi-variant enum (when remaining variants are
 // visibly uninhabited).
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 //@ edition:2021
 //@ run-pass
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 
 pub fn main() {
diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.svg b/tests/ui/codemap_tests/huge_multispan_highlight.svg
index 7b6dbb17c6f..12058176dc0 100644
--- a/tests/ui/codemap_tests/huge_multispan_highlight.svg
+++ b/tests/ui/codemap_tests/huge_multispan_highlight.svg
@@ -1,4 +1,4 @@
-<svg width="740px" height="848px" xmlns="http://www.w3.org/2000/svg">
+<svg width="818px" height="848px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
     .bg { background: #000000 }
diff --git a/tests/ui/coherence/re-rebalance-coherence.rs b/tests/ui/coherence/re-rebalance-coherence.rs
index 5383a634617..9c176d5b1b1 100644
--- a/tests/ui/coherence/re-rebalance-coherence.rs
+++ b/tests/ui/coherence/re-rebalance-coherence.rs
@@ -4,7 +4,6 @@
 extern crate re_rebalance_coherence_lib as lib;
 use lib::*;
 
-#[allow(dead_code)]
 struct Oracle;
 impl Backend for Oracle {}
 impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {}
diff --git a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.rs b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.rs
new file mode 100644
index 00000000000..311f507d3c7
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.rs
@@ -0,0 +1,28 @@
+// This ensures we don't ICE in situations like rust-lang/rust#126272.
+
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+
+use std::marker::ConstParamTy;
+
+#[derive(Debug, PartialEq, Eq, ConstParamTy)]
+//~^ ERROR the trait `ConstParamTy_`
+//~| ERROR the trait `ConstParamTy_`
+struct Foo {
+    nested: &'static Bar<dyn std::fmt::Debug>,
+    //~^ ERROR the size for values
+    //~| ERROR the size for values
+    //~| ERROR binary operation `==` cannot
+    //~| ERROR the trait bound `dyn Debug: Eq`
+    //~| ERROR the size for values
+}
+
+#[derive(Debug, PartialEq, Eq, ConstParamTy)]
+struct Bar<T>(T);
+
+struct Test<const F: Foo>;
+
+fn main() {
+    let x: Test<{ Foo { nested: &Bar(4) } }> = Test;
+    //~^ ERROR the size for values
+}
diff --git a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr
new file mode 100644
index 00000000000..1c30aa68e85
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr
@@ -0,0 +1,160 @@
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:12:13
+   |
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:8:32
+   |
+LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
+   |                                ^^^^^^^^^^^^
+...
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |     ----------------------------------------- this field does not implement `ConstParamTy_`
+   |
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:8:32
+   |
+LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
+   |                                ^^^^^^^^^^^^
+...
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |     ----------------------------------------- this field does not implement `ConstParamTy_`
+   |
+note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): Eq`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:12:13
+   |
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): Sized`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:12:13
+   |
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): UnsizedConstParamTy`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:12:13
+   |
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:12:5
+   |
+LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
+   |          ----- in this derive macro expansion
+...
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`, which is required by `&&'static Bar<(dyn Debug + 'static)>: Debug`
+   = help: the trait `Debug` is implemented for `Bar<T>`
+note: required for `Bar<(dyn Debug + 'static)>` to implement `Debug`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:20:10
+   |
+LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
+   |          ^^^^^
+LL | struct Bar<T>(T);
+   |            - unsatisfied trait bound introduced in this `derive` macro
+   = note: 2 redundant requirements hidden
+   = note: required for `&&'static Bar<(dyn Debug + 'static)>` to implement `Debug`
+   = note: required for the cast from `&&&'static Bar<(dyn Debug + 'static)>` to `&dyn Debug`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0369]: binary operation `==` cannot be applied to type `&Bar<dyn Debug>`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:12:5
+   |
+LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
+   |                 --------- in this derive macro expansion
+...
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `dyn Debug: Eq` is not satisfied
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:12:5
+   |
+LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
+   |                            -- in this derive macro expansion
+...
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `dyn Debug`, which is required by `&'static Bar<dyn Debug>: Eq`
+   |
+   = help: the trait `Eq` is implemented for `Bar<T>`
+note: required for `Bar<dyn Debug>` to implement `Eq`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:20:28
+   |
+LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
+   |                            ^^ unsatisfied trait bound introduced in this `derive` macro
+   = note: 1 redundant requirement hidden
+   = note: required for `&'static Bar<dyn Debug>` to implement `Eq`
+note: required by a bound in `AssertParamIsEq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:12:5
+   |
+LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
+   |                            -- in this derive macro expansion
+...
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `dyn Debug`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+   = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:26:33
+   |
+LL |     let x: Test<{ Foo { nested: &Bar(4) } }> = Test;
+   |                                 ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0204, E0277, E0369.
+For more information about an error, try `rustc --explain E0204`.
diff --git a/tests/ui/const-generics/cross_crate_complex.rs b/tests/ui/const-generics/cross_crate_complex.rs
index b44d889f5e9..d13b69aa0cf 100644
--- a/tests/ui/const-generics/cross_crate_complex.rs
+++ b/tests/ui/const-generics/cross_crate_complex.rs
@@ -11,7 +11,6 @@ async fn foo() {
     async_in_foo(async_out_foo::<4>().await).await;
 }
 
-#[allow(dead_code)]
 struct Faz<const N: usize>;
 
 impl<const N: usize> Foo<N> for Faz<N> {}
diff --git a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
index 5c9323261a9..9eb33acbb24 100644
--- a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
+++ b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
@@ -3,7 +3,7 @@ trait Trait {
 }
 impl Trait for () {
     fn foo<const M: u64>() {}
-    //~^ error: method `foo` has an incompatible generic parameter for trait
+    //~^ error: associated function `foo` has an incompatible generic parameter for trait
 }
 
 trait Other {
@@ -11,7 +11,7 @@ trait Other {
 }
 impl Other for () {
     fn bar<T>() {}
-    //~^ error: method `bar` has an incompatible generic parameter for trait
+    //~^ error: associated function `bar` has an incompatible generic parameter for trait
 }
 
 trait Uwu {
@@ -19,7 +19,7 @@ trait Uwu {
 }
 impl Uwu for () {
     fn baz<const N: i32>() {}
-    //~^ error: method `baz` has an incompatible generic parameter for trait
+    //~^ error: associated function `baz` has an incompatible generic parameter for trait
 }
 
 trait Aaaaaa {
@@ -27,7 +27,7 @@ trait Aaaaaa {
 }
 impl Aaaaaa for () {
     fn bbbb<T, const N: u32>() {}
-    //~^ error: method `bbbb` has an incompatible generic parameter for trait
+    //~^ error: associated function `bbbb` has an incompatible generic parameter for trait
 }
 
 trait Names {
@@ -35,7 +35,7 @@ trait Names {
 }
 impl Names for () {
     fn abcd<const N: u32, T>() {}
-    //~^ error: method `abcd` has an incompatible generic parameter for trait
+    //~^ error: associated function `abcd` has an incompatible generic parameter for trait
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
index 3455f2c8ea9..7ec162e1c29 100644
--- a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
+++ b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
@@ -1,4 +1,4 @@
-error[E0053]: method `foo` has an incompatible generic parameter for trait `Trait`
+error[E0053]: associated function `foo` has an incompatible generic parameter for trait `Trait`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
    |
 LL | trait Trait {
@@ -11,7 +11,7 @@ LL | impl Trait for () {
 LL |     fn foo<const M: u64>() {}
    |            ^^^^^^^^^^^^ found const parameter of type `u64`
 
-error[E0053]: method `bar` has an incompatible generic parameter for trait `Other`
+error[E0053]: associated function `bar` has an incompatible generic parameter for trait `Other`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
    |
 LL | trait Other {
@@ -24,7 +24,7 @@ LL | impl Other for () {
 LL |     fn bar<T>() {}
    |            ^ found type parameter
 
-error[E0053]: method `baz` has an incompatible generic parameter for trait `Uwu`
+error[E0053]: associated function `baz` has an incompatible generic parameter for trait `Uwu`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12
    |
 LL | trait Uwu {
@@ -37,7 +37,7 @@ LL | impl Uwu for () {
 LL |     fn baz<const N: i32>() {}
    |            ^^^^^^^^^^^^ found const parameter of type `i32`
 
-error[E0053]: method `bbbb` has an incompatible generic parameter for trait `Aaaaaa`
+error[E0053]: associated function `bbbb` has an incompatible generic parameter for trait `Aaaaaa`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:29:13
    |
 LL | trait Aaaaaa {
@@ -50,7 +50,7 @@ LL | impl Aaaaaa for () {
 LL |     fn bbbb<T, const N: u32>() {}
    |             ^ found type parameter
 
-error[E0053]: method `abcd` has an incompatible generic parameter for trait `Names`
+error[E0053]: associated function `abcd` has an incompatible generic parameter for trait `Names`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:37:13
    |
 LL | trait Names {
diff --git a/tests/ui/const-generics/defaults/repr-c-issue-82792.rs b/tests/ui/const-generics/defaults/repr-c-issue-82792.rs
index 4bf2fa761ea..c23187598bc 100644
--- a/tests/ui/const-generics/defaults/repr-c-issue-82792.rs
+++ b/tests/ui/const-generics/defaults/repr-c-issue-82792.rs
@@ -2,7 +2,6 @@
 
 //@ run-pass
 
-#[allow(dead_code)]
 #[repr(C)]
 pub struct Loaf<T: Sized, const N: usize = 1> {
     head: [T; N],
diff --git a/tests/ui/const-generics/generic_const_exprs/associated-consts.rs b/tests/ui/const-generics/generic_const_exprs/associated-consts.rs
index 50a6102c605..5d2198f50ad 100644
--- a/tests/ui/const-generics/generic_const_exprs/associated-consts.rs
+++ b/tests/ui/const-generics/generic_const_exprs/associated-consts.rs
@@ -16,8 +16,7 @@ impl BlockCipher for BarCipher {
     const BLOCK_SIZE: usize = 32;
 }
 
-#[allow(dead_code)]
-pub struct Block<C>(C);
+pub struct Block<C>(#[allow(dead_code)] C);
 
 pub fn test<C: BlockCipher, const M: usize>()
 where
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
index 8d59235e2f4..01529599d37 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr
@@ -1,4 +1,4 @@
-error: internal compiler error: compiler/rustc_const_eval/src/interpret/step.rs:LL:CC: SizeOf MIR operator called for unsized type dyn Debug
+error: internal compiler error: compiler/rustc_const_eval/src/interpret/operator.rs:LL:CC: unsized type for `NullaryOp::SizeOf`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
 Box<dyn Any>
diff --git a/tests/ui/const-generics/generic_const_exprs/no_where_clause.rs b/tests/ui/const-generics/generic_const_exprs/no_where_clause.rs
index 77cce66e4ec..53230469491 100644
--- a/tests/ui/const-generics/generic_const_exprs/no_where_clause.rs
+++ b/tests/ui/const-generics/generic_const_exprs/no_where_clause.rs
@@ -17,6 +17,7 @@ impl<const N: usize> Example<N> {
       a: [0.; N],
       b: [0.; complex_maths(N)],
       //~^ ERROR: unconstrained generic constant
+      //~| ERROR: unconstrained generic constant
     }
   }
 }
diff --git a/tests/ui/const-generics/generic_const_exprs/no_where_clause.stderr b/tests/ui/const-generics/generic_const_exprs/no_where_clause.stderr
index a2680eac039..88fc68a4d1b 100644
--- a/tests/ui/const-generics/generic_const_exprs/no_where_clause.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/no_where_clause.stderr
@@ -10,6 +10,17 @@ LL | pub struct Example<const N: usize> where [(); complex_maths(N)]: {
    |                                    +++++++++++++++++++++++++++++
 
 error: unconstrained generic constant
+  --> $DIR/no_where_clause.rs:18:10
+   |
+LL |       b: [0.; complex_maths(N)],
+   |          ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try adding a `where` bound
+   |
+LL |   pub fn new() -> Self where [(); complex_maths(N)]: {
+   |                        +++++++++++++++++++++++++++++
+
+error: unconstrained generic constant
   --> $DIR/no_where_clause.rs:18:15
    |
 LL |       b: [0.; complex_maths(N)],
@@ -20,5 +31,5 @@ help: try adding a `where` bound
 LL |   pub fn new() -> Self where [(); complex_maths(N)]: {
    |                        +++++++++++++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-86535-2.rs b/tests/ui/const-generics/issues/issue-86535-2.rs
index ab68c6b78df..8d064f3eeb1 100644
--- a/tests/ui/const-generics/issues/issue-86535-2.rs
+++ b/tests/ui/const-generics/issues/issue-86535-2.rs
@@ -9,7 +9,6 @@ pub trait Foo {
         [(); Self::ASSOC_C]:;
 }
 
-#[allow(dead_code)]
 struct Bar<const N: &'static ()>;
 impl<const N: &'static ()> Foo for Bar<N> {
     const ASSOC_C: usize = 3;
diff --git a/tests/ui/const-generics/issues/issue-86535.rs b/tests/ui/const-generics/issues/issue-86535.rs
index 9aaf7ddc9e8..62454f4a388 100644
--- a/tests/ui/const-generics/issues/issue-86535.rs
+++ b/tests/ui/const-generics/issues/issue-86535.rs
@@ -2,7 +2,6 @@
 #![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
 #![allow(incomplete_features, unused_variables)]
 
-#[allow(dead_code)]
 struct F<const S: &'static str>;
 impl<const S: &'static str> X for F<{ S }> {
     const W: usize = 3;
diff --git a/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs b/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs
index 35c41ae4615..419d605d0c8 100644
--- a/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs
+++ b/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs
@@ -6,7 +6,6 @@
 
 use std::mem::MaybeUninit;
 
-#[allow(dead_code)]
 #[repr(transparent)]
 pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>);
 
diff --git a/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs b/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
index 5628ae1be36..f4130319eea 100644
--- a/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
+++ b/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
@@ -1,8 +1,8 @@
 //@ run-pass
-
+#![allow(unreachable_patterns)]
 #![allow(dead_code)]
 
-enum Empty { }
+enum Empty {}
 enum Test1 {
     A(u8),
     B(Empty),
diff --git a/tests/ui/coroutine/invalid_attr_usage.rs b/tests/ui/coroutine/invalid_attr_usage.rs
new file mode 100644
index 00000000000..995a3aa3100
--- /dev/null
+++ b/tests/ui/coroutine/invalid_attr_usage.rs
@@ -0,0 +1,11 @@
+//! The `coroutine` attribute is only allowed on closures.
+
+#![feature(coroutines)]
+
+#[coroutine]
+//~^ ERROR: attribute should be applied to closures
+struct Foo;
+
+#[coroutine]
+//~^ ERROR: attribute should be applied to closures
+fn main() {}
diff --git a/tests/ui/coroutine/invalid_attr_usage.stderr b/tests/ui/coroutine/invalid_attr_usage.stderr
new file mode 100644
index 00000000000..316a0117e5d
--- /dev/null
+++ b/tests/ui/coroutine/invalid_attr_usage.stderr
@@ -0,0 +1,14 @@
+error: attribute should be applied to closures
+  --> $DIR/invalid_attr_usage.rs:5:1
+   |
+LL | #[coroutine]
+   | ^^^^^^^^^^^^
+
+error: attribute should be applied to closures
+  --> $DIR/invalid_attr_usage.rs:9:1
+   |
+LL | #[coroutine]
+   | ^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs
index 5701cc6055d..d5ac68ecf1b 100644
--- a/tests/ui/delegation/not-supported.rs
+++ b/tests/ui/delegation/not-supported.rs
@@ -53,7 +53,7 @@ mod generics {
         //~| ERROR method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
         reuse <F as Trait>::foo3;
         //~^ ERROR early bound generics are not supported for associated delegation items
-        //~| ERROR lifetime parameters or bounds on method `foo3` do not match the trait declaration
+        //~| ERROR lifetime parameters or bounds on associated function `foo3` do not match the trait declaration
     }
 
     struct GenericS<T>(T);
diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr
index e7ba9fc6719..14d6b374bd2 100644
--- a/tests/ui/delegation/not-supported.stderr
+++ b/tests/ui/delegation/not-supported.stderr
@@ -84,14 +84,14 @@ LL |         fn foo3<'a: 'a>(_: &'a u32) {}
 LL |         reuse <F as Trait>::foo3;
    |                             ^^^^
 
-error[E0195]: lifetime parameters or bounds on method `foo3` do not match the trait declaration
+error[E0195]: lifetime parameters or bounds on associated function `foo3` do not match the trait declaration
   --> $DIR/not-supported.rs:54:29
    |
 LL |         fn foo3<'a: 'a>(_: &'a u32) {}
-   |                -------- lifetimes in impl do not match this method in trait
+   |                -------- lifetimes in impl do not match this associated function in trait
 ...
 LL |         reuse <F as Trait>::foo3;
-   |                             ^^^^ lifetimes do not match method in trait
+   |                             ^^^^ lifetimes do not match associated function in trait
 
 error: delegation to a function with effect parameter is not supported yet
   --> $DIR/not-supported.rs:112:18
diff --git a/tests/ui/derives/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed.rs
index 58be4519720..d17b52842ce 100644
--- a/tests/ui/derives/deriving-with-repr-packed.rs
+++ b/tests/ui/derives/deriving-with-repr-packed.rs
@@ -22,25 +22,22 @@ struct Y(usize);
 struct X(Y);
 //~^ ERROR cannot move out of `self` which is behind a shared reference
 
-// This is currently allowed, but will be phased out at some point. From
-// `zerovec` within icu4x-0.9.0.
 #[derive(Debug)]
 #[repr(packed)]
 struct FlexZeroSlice {
     width: u8,
     data: [u8],
-    //~^ WARNING byte slice in a packed struct that derives a built-in trait
-    //~^^ this was previously accepted
+    //~^ ERROR cannot move
+    //~| ERROR cannot move
 }
 
-// Again, currently allowed, but will be phased out.
 #[derive(Debug)]
 #[repr(packed)]
 struct WithStr {
     width: u8,
     data: str,
-    //~^ WARNING string slice in a packed struct that derives a built-in trait
-    //~^^ this was previously accepted
+    //~^ ERROR cannot move
+    //~| ERROR cannot move
 }
 
 fn main() {}
diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr
index a8523d25cab..321ffb27eeb 100644
--- a/tests/ui/derives/deriving-with-repr-packed.stderr
+++ b/tests/ui/derives/deriving-with-repr-packed.stderr
@@ -1,32 +1,3 @@
-warning: byte slice in a packed struct that derives a built-in trait
-  --> $DIR/deriving-with-repr-packed.rs:31:5
-   |
-LL | #[derive(Debug)]
-   |          ----- in this derive macro expansion
-...
-LL |     data: [u8],
-   |     ^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
-   = help: consider implementing the trait by hand, or remove the `packed` attribute
-   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
-   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: string slice in a packed struct that derives a built-in trait
-  --> $DIR/deriving-with-repr-packed.rs:41:5
-   |
-LL | #[derive(Debug)]
-   |          ----- in this derive macro expansion
-...
-LL |     data: str,
-   |     ^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
-   = help: consider implementing the trait by hand, or remove the `packed` attribute
-   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-
 error[E0507]: cannot move out of `self` which is behind a shared reference
   --> $DIR/deriving-with-repr-packed.rs:22:10
    |
@@ -47,38 +18,43 @@ LL | struct X(Y);
    = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 1 previous error; 2 warnings emitted
+error[E0161]: cannot move a value of type `[u8]`
+  --> $DIR/deriving-with-repr-packed.rs:29:5
+   |
+LL |     data: [u8],
+   |     ^^^^^^^^^^ the size of `[u8]` cannot be statically determined
 
-For more information about this error, try `rustc --explain E0507`.
-Future incompatibility report: Future breakage diagnostic:
-warning: byte slice in a packed struct that derives a built-in trait
-  --> $DIR/deriving-with-repr-packed.rs:31:5
+error[E0507]: cannot move out of `self.data` which is behind a shared reference
+  --> $DIR/deriving-with-repr-packed.rs:29:5
    |
 LL | #[derive(Debug)]
    |          ----- in this derive macro expansion
 ...
 LL |     data: [u8],
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^^^ move occurs because `self.data` has type `[u8]`, which does not implement the `Copy` trait
+   |
+   = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0161]: cannot move a value of type `str`
+  --> $DIR/deriving-with-repr-packed.rs:38:5
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
-   = help: consider implementing the trait by hand, or remove the `packed` attribute
-   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
-   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL |     data: str,
+   |     ^^^^^^^^^ the size of `str` cannot be statically determined
 
-Future breakage diagnostic:
-warning: string slice in a packed struct that derives a built-in trait
-  --> $DIR/deriving-with-repr-packed.rs:41:5
+error[E0507]: cannot move out of `self.data` which is behind a shared reference
+  --> $DIR/deriving-with-repr-packed.rs:38:5
    |
 LL | #[derive(Debug)]
    |          ----- in this derive macro expansion
 ...
 LL |     data: str,
-   |     ^^^^^^^^^
+   |     ^^^^^^^^^ move occurs because `self.data` has type `str`, which does not implement the `Copy` trait
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
-   = help: consider implementing the trait by hand, or remove the `packed` attribute
-   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
-   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors
 
+Some errors have detailed explanations: E0161, E0507.
+For more information about an error, try `rustc --explain E0161`.
diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs
index 6fa4f74f2a5..eab2b4f1f53 100644
--- a/tests/ui/deriving/deriving-all-codegen.rs
+++ b/tests/ui/deriving/deriving-all-codegen.rs
@@ -73,16 +73,6 @@ impl Copy for PackedManualCopy {}
 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
 struct Unsized([u32]);
 
-// A packed struct with an unsized `[u8]` field. This is currently allowed, but
-// causes a warning and will be phased out at some point.
-#[derive(Debug, Hash)]
-#[repr(packed)]
-struct PackedUnsizedU8([u8]);
-//~^ WARNING byte slice in a packed struct that derives a built-in trait
-//~^^ WARNING byte slice in a packed struct that derives a built-in trait
-//~^^^ this was previously accepted
-//~^^^^ this was previously accepted
-
 trait Trait {
     type A;
 }
diff --git a/tests/ui/deriving/deriving-all-codegen.stderr b/tests/ui/deriving/deriving-all-codegen.stderr
deleted file mode 100644
index 503f0cae73b..00000000000
--- a/tests/ui/deriving/deriving-all-codegen.stderr
+++ /dev/null
@@ -1,63 +0,0 @@
-warning: byte slice in a packed struct that derives a built-in trait
-  --> $DIR/deriving-all-codegen.rs:80:24
-   |
-LL | #[derive(Debug, Hash)]
-   |          ----- in this derive macro expansion
-LL | #[repr(packed)]
-LL | struct PackedUnsizedU8([u8]);
-   |                        ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
-   = help: consider implementing the trait by hand, or remove the `packed` attribute
-   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
-   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: byte slice in a packed struct that derives a built-in trait
-  --> $DIR/deriving-all-codegen.rs:80:24
-   |
-LL | #[derive(Debug, Hash)]
-   |                 ---- in this derive macro expansion
-LL | #[repr(packed)]
-LL | struct PackedUnsizedU8([u8]);
-   |                        ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
-   = help: consider implementing the trait by hand, or remove the `packed` attribute
-   = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 2 warnings emitted
-
-Future incompatibility report: Future breakage diagnostic:
-warning: byte slice in a packed struct that derives a built-in trait
-  --> $DIR/deriving-all-codegen.rs:80:24
-   |
-LL | #[derive(Debug, Hash)]
-   |          ----- in this derive macro expansion
-LL | #[repr(packed)]
-LL | struct PackedUnsizedU8([u8]);
-   |                        ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
-   = help: consider implementing the trait by hand, or remove the `packed` attribute
-   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
-   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-warning: byte slice in a packed struct that derives a built-in trait
-  --> $DIR/deriving-all-codegen.rs:80:24
-   |
-LL | #[derive(Debug, Hash)]
-   |                 ---- in this derive macro expansion
-LL | #[repr(packed)]
-LL | struct PackedUnsizedU8([u8]);
-   |                        ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
-   = help: consider implementing the trait by hand, or remove the `packed` attribute
-   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
-   = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
-
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index 6b69b57c516..6503c870990 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -516,26 +516,6 @@ impl ::core::cmp::Ord for Unsized {
     }
 }
 
-// A packed struct with an unsized `[u8]` field. This is currently allowed, but
-// causes a warning and will be phased out at some point.
-#[repr(packed)]
-struct PackedUnsizedU8([u8]);
-#[automatically_derived]
-impl ::core::fmt::Debug for PackedUnsizedU8 {
-    #[inline]
-    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
-            "PackedUnsizedU8", &&self.0)
-    }
-}
-#[automatically_derived]
-impl ::core::hash::Hash for PackedUnsizedU8 {
-    #[inline]
-    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        ::core::hash::Hash::hash(&self.0, state)
-    }
-}
-
 trait Trait {
     type A;
 }
diff --git a/tests/ui/enum-discriminant/issue-61696.rs b/tests/ui/enum-discriminant/issue-61696.rs
index d200b4410ff..e93fd0e07f6 100644
--- a/tests/ui/enum-discriminant/issue-61696.rs
+++ b/tests/ui/enum-discriminant/issue-61696.rs
@@ -1,4 +1,5 @@
 //@ run-pass
+#![allow(unreachable_patterns)]
 
 pub enum Infallible {}
 
diff --git a/tests/ui/enum-discriminant/niche.rs b/tests/ui/enum-discriminant/niche.rs
index 15d227fd826..f9c4a135a6f 100644
--- a/tests/ui/enum-discriminant/niche.rs
+++ b/tests/ui/enum-discriminant/niche.rs
@@ -1,4 +1,5 @@
 //@ run-pass
+#![allow(unreachable_patterns)]
 
 //! Make sure that we read and write enum discriminants correctly for corner cases caused
 //! by layout optimizations.
diff --git a/tests/ui/error-codes/E0049.stderr b/tests/ui/error-codes/E0049.stderr
index c0cd31faa90..83a30aa0a78 100644
--- a/tests/ui/error-codes/E0049.stderr
+++ b/tests/ui/error-codes/E0049.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter
+error[E0049]: associated function `foo` has 0 type parameters but its trait declaration has 1 type parameter
   --> $DIR/E0049.rs:8:11
    |
 LL |     fn foo<T: Default>(x: T) -> Self;
@@ -7,7 +7,7 @@ LL |     fn foo<T: Default>(x: T) -> Self;
 LL |     fn foo(x: bool) -> Self { Bar }
    |           ^ found 0 type parameters
 
-error[E0049]: method `fuzz` has 0 type parameters but its trait declaration has 2 type parameters
+error[E0049]: associated function `fuzz` has 0 type parameters but its trait declaration has 2 type parameters
   --> $DIR/E0049.rs:18:12
    |
 LL |     fn fuzz<A: Default, B>(x: A, y: B) -> Self;
diff --git a/tests/ui/error-codes/E0195.rs b/tests/ui/error-codes/E0195.rs
index f712ee42b8c..a7e51dff2f3 100644
--- a/tests/ui/error-codes/E0195.rs
+++ b/tests/ui/error-codes/E0195.rs
@@ -1,13 +1,13 @@
 trait Trait {
     fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
-    //~^ NOTE lifetimes in impl do not match this method in trait
+    //~^ NOTE lifetimes in impl do not match this associated function in trait
 }
 
 struct Foo;
 
 impl Trait for Foo {
     fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
-    //~^ NOTE lifetimes do not match method in trait
+    //~^ NOTE lifetimes do not match associated function in trait
     }
 }
 
diff --git a/tests/ui/error-codes/E0195.stderr b/tests/ui/error-codes/E0195.stderr
index b88064b7f90..9767dee9aec 100644
--- a/tests/ui/error-codes/E0195.stderr
+++ b/tests/ui/error-codes/E0195.stderr
@@ -1,11 +1,11 @@
-error[E0195]: lifetime parameters or bounds on method `bar` do not match the trait declaration
+error[E0195]: lifetime parameters or bounds on associated function `bar` do not match the trait declaration
   --> $DIR/E0195.rs:9:11
    |
 LL |     fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
-   |           ---------- lifetimes in impl do not match this method in trait
+   |           ---------- lifetimes in impl do not match this associated function in trait
 ...
 LL |     fn bar<'a,'b>(x: &'a str, y: &'b str) {
-   |           ^^^^^^^ lifetimes do not match method in trait
+   |           ^^^^^^^ lifetimes do not match associated function in trait
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0283.stderr b/tests/ui/error-codes/E0283.stderr
index fc08395a2b0..381eca5f2a4 100644
--- a/tests/ui/error-codes/E0283.stderr
+++ b/tests/ui/error-codes/E0283.stderr
@@ -7,10 +7,12 @@ LL |     fn create() -> u32;
 LL |     let cont: u32 = Coroutine::create();
    |                     ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
    |
-help: use a fully-qualified path to a specific available implementation
+help: use a fully-qualified path to one of the available implementations
    |
-LL |     let cont: u32 = </* self type */ as Coroutine>::create();
-   |                     +++++++++++++++++++          +
+LL |     let cont: u32 = <Impl as Coroutine>::create();
+   |                     ++++++++          +
+LL |     let cont: u32 = <AnotherImpl as Coroutine>::create();
+   |                     +++++++++++++++          +
 
 error[E0283]: type annotations needed
   --> $DIR/E0283.rs:35:24
diff --git a/tests/ui/error-codes/E0790.stderr b/tests/ui/error-codes/E0790.stderr
index 6338a10b6af..106554b2425 100644
--- a/tests/ui/error-codes/E0790.stderr
+++ b/tests/ui/error-codes/E0790.stderr
@@ -63,10 +63,12 @@ LL |     fn my_fn();
 LL |     MyTrait2::my_fn();
    |     ^^^^^^^^^^^^^^^^^ cannot call associated function of trait
    |
-help: use a fully-qualified path to a specific available implementation
+help: use a fully-qualified path to one of the available implementations
    |
-LL |     </* self type */ as MyTrait2>::my_fn();
-   |     +++++++++++++++++++         +
+LL |     <Impl1 as MyTrait2>::my_fn();
+   |     +++++++++         +
+LL |     <Impl2 as MyTrait2>::my_fn();
+   |     +++++++++         +
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/extern/extern-types-field-offset.run.stderr b/tests/ui/extern/extern-types-field-offset.run.stderr
index 1b04b860db5..f1407398980 100644
--- a/tests/ui/extern/extern-types-field-offset.run.stderr
+++ b/tests/ui/extern/extern-types-field-offset.run.stderr
@@ -1,4 +1,4 @@
-thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL:
+thread 'main' panicked at core/src/panicking.rs:$LINE:$COL:
 attempted to compute the size or alignment of extern type `Opaque`
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 thread caused non-unwinding panic. aborting.
diff --git a/tests/ui/extern/extern-types-size_of_val.align.run.stderr b/tests/ui/extern/extern-types-size_of_val.align.run.stderr
index 20c4d8785e8..faad1aa13fa 100644
--- a/tests/ui/extern/extern-types-size_of_val.align.run.stderr
+++ b/tests/ui/extern/extern-types-size_of_val.align.run.stderr
@@ -1,4 +1,4 @@
-thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL:
+thread 'main' panicked at core/src/panicking.rs:$LINE:$COL:
 attempted to compute the size or alignment of extern type `A`
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 thread caused non-unwinding panic. aborting.
diff --git a/tests/ui/extern/extern-types-size_of_val.size.run.stderr b/tests/ui/extern/extern-types-size_of_val.size.run.stderr
index 20c4d8785e8..faad1aa13fa 100644
--- a/tests/ui/extern/extern-types-size_of_val.size.run.stderr
+++ b/tests/ui/extern/extern-types-size_of_val.size.run.stderr
@@ -1,4 +1,4 @@
-thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL:
+thread 'main' panicked at core/src/panicking.rs:$LINE:$COL:
 attempted to compute the size or alignment of extern type `A`
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 thread caused non-unwinding panic. aborting.
diff --git a/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.stderr b/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.stderr
deleted file mode 100644
index 308de269293..00000000000
--- a/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/feature-gate-default_type_parameter_fallback.rs:3:8
-   |
-LL | fn avg<T=i32>(_: T) {}
-   |        ^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
-
-error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/feature-gate-default_type_parameter_fallback.rs:8:6
-   |
-LL | impl<T=i32> S<T> {}
-   |      ^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs
index f0cc9ea7055..79891593692 100644
--- a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs
+++ b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs
@@ -5,5 +5,5 @@ fn foo() -> Result<u32, !> {
 }
 
 fn main() {
-    let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding
+    let Ok(_x) = &foo(); //~ ERROR refutable pattern in local binding
 }
diff --git a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
index d34f257c8d9..4836ffe1723 100644
--- a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
+++ b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
@@ -1,16 +1,16 @@
 error[E0005]: refutable pattern in local binding
   --> $DIR/feature-gate-exhaustive-patterns.rs:8:9
    |
-LL |     let Ok(_x) = foo();
-   |         ^^^^^^ pattern `Err(_)` not covered
+LL |     let Ok(_x) = &foo();
+   |         ^^^^^^ pattern `&Err(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `Result<u32, !>`
+   = note: the matched value is of type `&Result<u32, !>`
 help: you might want to use `let else` to handle the variant that isn't matched
    |
-LL |     let Ok(_x) = foo() else { todo!() };
-   |                        ++++++++++++++++
+LL |     let Ok(_x) = &foo() else { todo!() };
+   |                         ++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-sha512_sm_x86.rs b/tests/ui/feature-gates/feature-gate-sha512_sm_x86.rs
new file mode 100644
index 00000000000..176a40ecf53
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-sha512_sm_x86.rs
@@ -0,0 +1,6 @@
+//@ only-x86_64
+#[target_feature(enable = "sha512")]
+//~^ ERROR: currently unstable
+unsafe fn foo() {}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-sha512_sm_x86.stderr b/tests/ui/feature-gates/feature-gate-sha512_sm_x86.stderr
new file mode 100644
index 00000000000..da9eea095a3
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-sha512_sm_x86.stderr
@@ -0,0 +1,13 @@
+error[E0658]: the target feature `sha512` is currently unstable
+  --> $DIR/feature-gate-sha512_sm_x86.rs:2:18
+   |
+LL | #[target_feature(enable = "sha512")]
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #126624 <https://github.com/rust-lang/rust/issues/126624> for more information
+   = help: add `#![feature(sha512_sm_x86)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs
deleted file mode 100644
index 3ea62e875b8..00000000000
--- a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-unsafe extern "C" {
-    //~^ ERROR extern block cannot be declared unsafe
-}
-
-// We can't gate `unsafe extern` blocks themselves since they were previously
-// allowed, but we should gate the `safe` soft keyword.
-#[cfg(any())]
-unsafe extern "C" {
-    safe fn foo();
-    //~^ ERROR `unsafe extern {}` blocks and `safe` keyword are experimental
-}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr
deleted file mode 100644
index 56534946308..00000000000
--- a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: extern block cannot be declared unsafe
-  --> $DIR/feature-gate-unsafe-extern-blocks.rs:1:1
-   |
-LL | unsafe extern "C" {
-   | ^^^^^^
-   |
-   = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
-   = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
-  --> $DIR/feature-gate-unsafe-extern-blocks.rs:9:5
-   |
-LL |     safe fn foo();
-   |     ^^^^
-   |
-   = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
-   = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs
index a7489f6fbaf..38be3250c7d 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs
@@ -5,6 +5,7 @@ trait Trait<'a>: 'a {
 // if the `T: 'a` bound gets implied we would probably get ub here again
 impl<'a, T> Trait<'a> for T {
     //~^ ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
     type Type = ();
 }
 
diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
index b898df0835c..b2aa1abbbdb 100644
--- a/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
+++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
@@ -16,8 +16,21 @@ help: consider adding an explicit lifetime bound
 LL | impl<'a, T: 'a> Trait<'a> for T {
    |           ++++
 
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:27
+   |
+LL | impl<'a, T> Trait<'a> for T {
+   |      --                   ^ ...so that the type `T` will meet its required lifetime bounds
+   |      |
+   |      the parameter type `T` must be valid for the lifetime `'a` as defined here...
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL | impl<'a, T: 'a> Trait<'a> for T {
+   |           ++++
+
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:21:10
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:22:10
    |
 LL |     let x = String::from("Hello World!");
    |         - binding `x` declared here
@@ -33,7 +46,7 @@ help: consider cloning the value if the performance cost is acceptable
 LL |     let y = f(&x.clone(), ());
    |                 ++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0309, E0505.
 For more information about an error, try `rustc --explain E0309`.
diff --git a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs
index 285493132b6..946cb1a62b7 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs
+++ b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs
@@ -8,7 +8,7 @@ impl<T> X for T { //~ ERROR: not all trait items implemented
   fn foo<'a, T1: X<Y = T1>>(t : T1) -> T1::Y<'a> {
     //~^ ERROR missing generics for associated type
     //~^^ ERROR missing generics for associated type
-    //~| ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters
+    //~| ERROR associated function `foo` has 1 type parameter but its trait declaration has 0 type parameters
     t
   }
 }
diff --git a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr
index 6a600aee11f..72c2bdc72a2 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr
+++ b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
+error[E0049]: associated function `foo` has 1 type parameter but its trait declaration has 0 type parameters
   --> $DIR/gat-trait-path-missing-lifetime.rs:8:10
    |
 LL |   fn foo<'a>(t : Self::Y<'a>) -> Self::Y<'a> { t }
diff --git a/tests/ui/generic-associated-types/issue-71176.rs b/tests/ui/generic-associated-types/issue-71176.rs
index e58b6f6091e..b33fda8e154 100644
--- a/tests/ui/generic-associated-types/issue-71176.rs
+++ b/tests/ui/generic-associated-types/issue-71176.rs
@@ -16,6 +16,6 @@ struct Holder<B> {
 
 fn main() {
     Holder {
-        inner: Box::new(()),
+        inner: Box::new(()), //~ ERROR: the trait `Provider` cannot be made into an object
     };
 }
diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr
index a1913bb618b..9f83c162c02 100644
--- a/tests/ui/generic-associated-types/issue-71176.stderr
+++ b/tests/ui/generic-associated-types/issue-71176.stderr
@@ -64,7 +64,23 @@ LL |     type A<'a>;
    = help: consider moving `A` to another trait
    = help: only type `()` implements the trait, consider using it directly instead
 
-error: aborting due to 4 previous errors
+error[E0038]: the trait `Provider` cannot be made into an object
+  --> $DIR/issue-71176.rs:19:16
+   |
+LL |         inner: Box::new(()),
+   |                ^^^^^^^^^^^^ `Provider` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-71176.rs:2:10
+   |
+LL | trait Provider {
+   |       -------- this trait cannot be made into an object...
+LL |     type A<'a>;
+   |          ^ ...because it contains the generic associated type `A`
+   = help: consider moving `A` to another trait
+   = help: only type `()` implements the trait, consider using it directly instead
+
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0038, E0107.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/generic-associated-types/missing-bounds.fixed b/tests/ui/generic-associated-types/missing-bounds.fixed
index ff69016d862..703d3c1e0fb 100644
--- a/tests/ui/generic-associated-types/missing-bounds.fixed
+++ b/tests/ui/generic-associated-types/missing-bounds.fixed
@@ -2,7 +2,6 @@
 
 use std::ops::Add;
 
-#[allow(dead_code)]
 struct A<B>(B);
 
 impl<B> Add for A<B> where B: Add<Output = B> {
@@ -13,7 +12,6 @@ impl<B> Add for A<B> where B: Add<Output = B> {
     }
 }
 
-#[allow(dead_code)]
 struct C<B>(B);
 
 impl<B: Add<Output = B>> Add for C<B> {
@@ -24,7 +22,6 @@ impl<B: Add<Output = B>> Add for C<B> {
     }
 }
 
-#[allow(dead_code)]
 struct D<B>(B);
 
 impl<B: std::ops::Add<Output = B>> Add for D<B> {
@@ -35,7 +32,6 @@ impl<B: std::ops::Add<Output = B>> Add for D<B> {
     }
 }
 
-#[allow(dead_code)]
 struct E<B>(B);
 
 impl<B: Add<Output = B>> Add for E<B> where B: Add<Output = B> {
diff --git a/tests/ui/generic-associated-types/missing-bounds.rs b/tests/ui/generic-associated-types/missing-bounds.rs
index 1f83356c2fa..f40b4228873 100644
--- a/tests/ui/generic-associated-types/missing-bounds.rs
+++ b/tests/ui/generic-associated-types/missing-bounds.rs
@@ -2,7 +2,6 @@
 
 use std::ops::Add;
 
-#[allow(dead_code)]
 struct A<B>(B);
 
 impl<B> Add for A<B> where B: Add {
@@ -13,7 +12,6 @@ impl<B> Add for A<B> where B: Add {
     }
 }
 
-#[allow(dead_code)]
 struct C<B>(B);
 
 impl<B: Add> Add for C<B> {
@@ -24,7 +22,6 @@ impl<B: Add> Add for C<B> {
     }
 }
 
-#[allow(dead_code)]
 struct D<B>(B);
 
 impl<B> Add for D<B> {
@@ -35,7 +32,6 @@ impl<B> Add for D<B> {
     }
 }
 
-#[allow(dead_code)]
 struct E<B>(B);
 
 impl<B: Add> Add for E<B> where <B as Add>::Output = B {
diff --git a/tests/ui/generic-associated-types/missing-bounds.stderr b/tests/ui/generic-associated-types/missing-bounds.stderr
index 0f0dc24c06c..1d7d80d1b07 100644
--- a/tests/ui/generic-associated-types/missing-bounds.stderr
+++ b/tests/ui/generic-associated-types/missing-bounds.stderr
@@ -1,5 +1,5 @@
 error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/missing-bounds.rs:41:33
+  --> $DIR/missing-bounds.rs:37:33
    |
 LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^ not supported
@@ -11,7 +11,7 @@ LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
    |                                 ~~~~~~~~~~~~~~~~~~
 
 error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:12:11
+  --> $DIR/missing-bounds.rs:11:11
    |
 LL | impl<B> Add for A<B> where B: Add {
    |      - expected this type parameter
@@ -24,14 +24,14 @@ LL |         A(self.0 + rhs.0)
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
 help: the type constructed contains `<B as Add>::Output` due to the type of the argument passed
-  --> $DIR/missing-bounds.rs:12:9
+  --> $DIR/missing-bounds.rs:11:9
    |
 LL |         A(self.0 + rhs.0)
    |         ^^--------------^
    |           |
    |           this argument influences the type of `A`
 note: tuple struct defined here
-  --> $DIR/missing-bounds.rs:6:8
+  --> $DIR/missing-bounds.rs:5:8
    |
 LL | struct A<B>(B);
    |        ^
@@ -41,7 +41,7 @@ LL | impl<B> Add for A<B> where B: Add<Output = B> {
    |                                  ++++++++++++
 
 error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:23:14
+  --> $DIR/missing-bounds.rs:21:14
    |
 LL | impl<B: Add> Add for C<B> {
    |      - expected this type parameter
@@ -54,7 +54,7 @@ LL |         Self(self.0 + rhs.0)
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
 note: tuple struct defined here
-  --> $DIR/missing-bounds.rs:17:8
+  --> $DIR/missing-bounds.rs:15:8
    |
 LL | struct C<B>(B);
    |        ^
@@ -64,7 +64,7 @@ LL | impl<B: Add<Output = B>> Add for C<B> {
    |            ++++++++++++
 
 error[E0369]: cannot add `B` to `B`
-  --> $DIR/missing-bounds.rs:34:21
+  --> $DIR/missing-bounds.rs:31:21
    |
 LL |         Self(self.0 + rhs.0)
    |              ------ ^ ----- B
@@ -77,7 +77,7 @@ LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
    |       +++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:46:14
+  --> $DIR/missing-bounds.rs:42:14
    |
 LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
    |      - expected this type parameter
@@ -90,7 +90,7 @@ LL |         Self(self.0 + rhs.0)
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
 note: tuple struct defined here
-  --> $DIR/missing-bounds.rs:39:8
+  --> $DIR/missing-bounds.rs:35:8
    |
 LL | struct E<B>(B);
    |        ^
diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr
index 5c1778bc485..bfed4cd6650 100644
--- a/tests/ui/hygiene/panic-location.run.stderr
+++ b/tests/ui/hygiene/panic-location.run.stderr
@@ -1,3 +1,3 @@
-thread 'main' panicked at library/alloc/src/raw_vec.rs:LL:CC:
+thread 'main' panicked at alloc/src/raw_vec.rs:LL:CC:
 capacity overflow
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed
index 3c4499f0173..886fc1d0058 100644
--- a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed
+++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed
@@ -1,8 +1,6 @@
 //@ run-rustfix
 
-#[allow(dead_code)]
 struct S<T>(T);
-#[allow(dead_code)]
 struct S2;
 
 impl<T: Default> Default for S<T> {
diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs
index ac078329524..f3271993867 100644
--- a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs
+++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs
@@ -1,8 +1,6 @@
 //@ run-rustfix
 
-#[allow(dead_code)]
 struct S<T>(T);
-#[allow(dead_code)]
 struct S2;
 
 impl<T: Default> impl Default for S<T> {
diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr
index 91c7da5a04f..5aafc8b64d4 100644
--- a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr
+++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr
@@ -1,23 +1,23 @@
 error: unexpected `impl` keyword
-  --> $DIR/extra-impl-in-trait-impl.rs:8:18
+  --> $DIR/extra-impl-in-trait-impl.rs:6:18
    |
 LL | impl<T: Default> impl Default for S<T> {
    |                  ^^^^^ help: remove the extra `impl`
    |
 note: this is parsed as an `impl Trait` type, but a trait is expected at this position
-  --> $DIR/extra-impl-in-trait-impl.rs:8:18
+  --> $DIR/extra-impl-in-trait-impl.rs:6:18
    |
 LL | impl<T: Default> impl Default for S<T> {
    |                  ^^^^^^^^^^^^
 
 error: unexpected `impl` keyword
-  --> $DIR/extra-impl-in-trait-impl.rs:14:6
+  --> $DIR/extra-impl-in-trait-impl.rs:12:6
    |
 LL | impl impl Default for S2 {
    |      ^^^^^ help: remove the extra `impl`
    |
 note: this is parsed as an `impl Trait` type, but a trait is expected at this position
-  --> $DIR/extra-impl-in-trait-impl.rs:14:6
+  --> $DIR/extra-impl-in-trait-impl.rs:12:6
    |
 LL | impl impl Default for S2 {
    |      ^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs b/tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs
new file mode 100644
index 00000000000..d7b62436d2d
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs
@@ -0,0 +1,29 @@
+#![feature(precise_capturing)]
+
+use std::future::Future;
+use std::pin::Pin;
+
+trait MyTrait {
+    fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32>;
+}
+
+trait ErasedMyTrait {
+    fn foo<'life0, 'life1, 'dynosaur>(&'life0 self, x: &'life1 i32)
+    -> Pin<Box<dyn Future<Output = i32> + 'dynosaur>>
+    where
+        'life0: 'dynosaur,
+        'life1: 'dynosaur;
+}
+
+struct DynMyTrait<T: ErasedMyTrait> {
+    ptr: T,
+}
+
+impl<T: ErasedMyTrait> MyTrait for DynMyTrait<T> {
+    fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32> {
+        self.ptr.foo(x)
+        //~^ ERROR hidden type for `impl Future<Output = i32>` captures lifetime that does not appear in bounds
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/cannot-capture-intersection.stderr b/tests/ui/impl-trait/in-trait/cannot-capture-intersection.stderr
new file mode 100644
index 00000000000..92ef66c5504
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/cannot-capture-intersection.stderr
@@ -0,0 +1,13 @@
+error[E0700]: hidden type for `impl Future<Output = i32>` captures lifetime that does not appear in bounds
+  --> $DIR/cannot-capture-intersection.rs:24:9
+   |
+LL |     fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32> {
+   |                                             ------------------------- opaque type defined here
+LL |         self.ptr.foo(x)
+   |         ^^^^^^^^^^^^^^^
+   |
+   = note: hidden type `Pin<Box<dyn Future<Output = i32>>>` captures lifetime `'_`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
index d9fac0238e1..0477de3315a 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
@@ -6,7 +6,7 @@ trait Foo {
 
 impl Foo for S {
     fn bar() -> impl Sized {}
-    //~^ ERROR method `bar` has 0 type parameters but its trait declaration has 1 type parameter
+    //~^ ERROR associated function `bar` has 0 type parameters but its trait declaration has 1 type parameter
 }
 
 fn main() {
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
index eed4c07710e..ca67db40362 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter
+error[E0049]: associated function `bar` has 0 type parameters but its trait declaration has 1 type parameter
   --> $DIR/trait-more-generics-than-impl.rs:8:11
    |
 LL |     fn bar<T>() -> impl Sized;
diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
index 4d4ba58c974..b7cee7d0b1f 100644
--- a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
+++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
@@ -2,17 +2,12 @@ error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does n
   --> $DIR/ordinary-bounds-unrelated.rs:28:33
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
-   |                     --                                                   ------------------ opaque type defined here
-   |                     |
-   |                     hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+   |                                                                          ------------------ opaque type defined here
 ...
 LL |     if condition() { a } else { b }
    |                                 ^
    |
-help: to declare that `impl Trait<'d, 'e>` captures `'b`, you can add an explicit `'b` lifetime bound
-   |
-LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
-   |                                                                                             ++++
+   = note: hidden type `Ordinary<'_>` captures lifetime `'_`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
index 060eaa7e64a..d1190da6c9f 100644
--- a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
+++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
@@ -2,17 +2,12 @@ error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does n
   --> $DIR/ordinary-bounds-unsuited.rs:31:33
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-   |                     --                                       ------------------ opaque type defined here
-   |                     |
-   |                     hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+   |                                                              ------------------ opaque type defined here
 ...
 LL |     if condition() { a } else { b }
    |                                 ^
    |
-help: to declare that `impl Trait<'a, 'b>` captures `'b`, you can add an explicit `'b` lifetime bound
-   |
-LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
-   |                                                                                 ++++
+   = note: hidden type `Ordinary<'_>` captures lifetime `'_`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr
index f0d259d01de..1fb69db98c1 100644
--- a/tests/ui/impl-trait/where-allowed.stderr
+++ b/tests/ui/impl-trait/where-allowed.stderr
@@ -433,3 +433,25 @@ error: aborting due to 50 previous errors
 
 Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0599, E0658, E0666.
 For more information about an error, try `rustc --explain E0053`.
+Future incompatibility report: Future breakage diagnostic:
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/where-allowed.rs:239:7
+   |
+LL | impl <T = impl Debug> T {}
+   |       ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
+Future breakage diagnostic:
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/where-allowed.rs:246:36
+   |
+LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
+   |                                    ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
diff --git a/tests/ui/inline-const/using-late-bound-from-closure.rs b/tests/ui/inline-const/using-late-bound-from-closure.rs
new file mode 100644
index 00000000000..2b12b2e26a2
--- /dev/null
+++ b/tests/ui/inline-const/using-late-bound-from-closure.rs
@@ -0,0 +1,16 @@
+// Test for ICE: cannot convert ReLateParam to a region vid
+// https://github.com/rust-lang/rust/issues/125873
+
+#![feature(closure_lifetime_binder)]
+fn foo() {
+    let a = for<'a> |b: &'a ()| -> &'a () {
+        const {
+            let awd = ();
+            let _: &'a () = &awd;
+            //~^ `awd` does not live long enough
+        };
+        b
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/inline-const/using-late-bound-from-closure.stderr b/tests/ui/inline-const/using-late-bound-from-closure.stderr
new file mode 100644
index 00000000000..d6e1579aa34
--- /dev/null
+++ b/tests/ui/inline-const/using-late-bound-from-closure.stderr
@@ -0,0 +1,19 @@
+error[E0597]: `awd` does not live long enough
+  --> $DIR/using-late-bound-from-closure.rs:9:29
+   |
+LL |     let a = for<'a> |b: &'a ()| -> &'a () {
+   |                 -- lifetime `'a` defined here
+LL |         const {
+LL |             let awd = ();
+   |                 --- binding `awd` declared here
+LL |             let _: &'a () = &awd;
+   |                    ------   ^^^^ borrowed value does not live long enough
+   |                    |
+   |                    type annotation requires that `awd` is borrowed for `'a`
+LL |
+LL |         };
+   |         - `awd` dropped here while still borrowed
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/issues/issue-19380.rs b/tests/ui/issues/issue-19380.rs
index fce737cba18..8b3fe4d2b09 100644
--- a/tests/ui/issues/issue-19380.rs
+++ b/tests/ui/issues/issue-19380.rs
@@ -15,5 +15,6 @@ struct Bar {
 const FOO : Foo = Foo;
 const BAR : Bar = Bar { foos: &[&FOO]};
 //~^ ERROR E0038
+//~| ERROR E0038
 
 fn main() { }
diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr
index f6244d9d44f..1d7aa6bd459 100644
--- a/tests/ui/issues/issue-19380.stderr
+++ b/tests/ui/issues/issue-19380.stderr
@@ -45,6 +45,29 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o
 LL |   fn qiz() where Self: Sized;
    |            +++++++++++++++++
 
-error: aborting due to 2 previous errors
+error[E0038]: the trait `Qiz` cannot be made into an object
+  --> $DIR/issue-19380.rs:16:31
+   |
+LL | const BAR : Bar = Bar { foos: &[&FOO]};
+   |                               ^^^^^^^ `Qiz` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-19380.rs:2:6
+   |
+LL | trait Qiz {
+   |       --- this trait cannot be made into an object...
+LL |   fn qiz();
+   |      ^^^ ...because associated function `qiz` has no `self` parameter
+   = help: only type `Foo` implements the trait, consider using it directly instead
+help: consider turning `qiz` into a method by giving it a `&self` argument
+   |
+LL |   fn qiz(&self);
+   |          +++++
+help: alternatively, consider constraining `qiz` so it does not apply to trait objects
+   |
+LL |   fn qiz() where Self: Sized;
+   |            +++++++++++++++++
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/issues/issue-26812.rs b/tests/ui/issues/issue-26812.rs
index 3391ea4b350..e0723e016b3 100644
--- a/tests/ui/issues/issue-26812.rs
+++ b/tests/ui/issues/issue-26812.rs
@@ -1,6 +1,6 @@
-#![feature(default_type_parameter_fallback)]
-
 fn avg<T=T::Item>(_: T) {}
 //~^ ERROR generic parameters with a default cannot use forward declared identifiers
+//~| ERROR defaults for type parameters
+//~| WARN previously accepted
 
 fn main() {}
diff --git a/tests/ui/issues/issue-26812.stderr b/tests/ui/issues/issue-26812.stderr
index c2a3d4b83d5..4a18b23fd8b 100644
--- a/tests/ui/issues/issue-26812.stderr
+++ b/tests/ui/issues/issue-26812.stderr
@@ -1,9 +1,30 @@
 error[E0128]: generic parameters with a default cannot use forward declared identifiers
-  --> $DIR/issue-26812.rs:3:10
+  --> $DIR/issue-26812.rs:1:10
    |
 LL | fn avg<T=T::Item>(_: T) {}
    |          ^^^^^^^ defaulted generic parameters cannot be forward declared
 
-error: aborting due to 1 previous error
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/issue-26812.rs:1:8
+   |
+LL | fn avg<T=T::Item>(_: T) {}
+   |        ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0128`.
+Future incompatibility report: Future breakage diagnostic:
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/issue-26812.rs:1:8
+   |
+LL | fn avg<T=T::Item>(_: T) {}
+   |        ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
diff --git a/tests/ui/issues/issue-5708.rs b/tests/ui/issues/issue-5708.rs
index 89ea9fbdcd8..ce9ef78ffcd 100644
--- a/tests/ui/issues/issue-5708.rs
+++ b/tests/ui/issues/issue-5708.rs
@@ -44,7 +44,6 @@ pub trait MyTrait<T> {
     fn dummy(&self, t: T) -> T { panic!() }
 }
 
-#[allow(dead_code)]
 pub struct MyContainer<'a, T:'a> {
     foos: Vec<&'a (dyn MyTrait<T>+'a)> ,
 }
diff --git a/tests/ui/json/json-bom-plus-crlf-multifile.stderr b/tests/ui/json/json-bom-plus-crlf-multifile.stderr
index 2ed26f9a8a5..9c88a7e5a25 100644
--- a/tests/ui/json/json-bom-plus-crlf-multifile.stderr
+++ b/tests/ui/json/json-bom-plus-crlf-multifile.stderr
@@ -24,7 +24,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":622,"byte_end":623,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":613,"byte_end":619,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":623,"byte_end":623,"line_start":17,"line_end":17,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":622,"byte_end":623,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":613,"byte_end":619,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":623,"byte_end":623,"line_start":17,"line_end":17,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -52,7 +52,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":682,"byte_end":683,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":673,"byte_end":679,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":683,"byte_end":683,"line_start":19,"line_end":19,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":682,"byte_end":683,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":673,"byte_end":679,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":683,"byte_end":683,"line_start":19,"line_end":19,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -80,7 +80,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":746,"byte_end":747,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":736,"byte_end":742,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":747,"byte_end":747,"line_start":23,"line_end":23,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":746,"byte_end":747,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":736,"byte_end":742,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":747,"byte_end":747,"line_start":23,"line_end":23,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -108,7 +108,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":802,"byte_end":810,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":793,"byte_end":799,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":802,"byte_end":810,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":793,"byte_end":799,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types: expected `String`, found `()`
 "}
 {"$message_type":"diagnostic","message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
 "}
diff --git a/tests/ui/json/json-bom-plus-crlf.stderr b/tests/ui/json/json-bom-plus-crlf.stderr
index b5e6f658616..cd1e3665b3e 100644
--- a/tests/ui/json/json-bom-plus-crlf.stderr
+++ b/tests/ui/json/json-bom-plus-crlf.stderr
@@ -24,7 +24,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":607,"byte_end":608,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":598,"byte_end":604,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":608,"byte_end":608,"line_start":16,"line_end":16,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":607,"byte_end":608,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":598,"byte_end":604,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":608,"byte_end":608,"line_start":16,"line_end":16,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -52,7 +52,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":667,"byte_end":668,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":658,"byte_end":664,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":668,"byte_end":668,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":667,"byte_end":668,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":658,"byte_end":664,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":668,"byte_end":668,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -80,7 +80,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":731,"byte_end":732,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":721,"byte_end":727,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":732,"byte_end":732,"line_start":22,"line_end":22,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":731,"byte_end":732,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":721,"byte_end":727,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":732,"byte_end":732,"line_start":22,"line_end":22,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -108,7 +108,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":787,"byte_end":795,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":778,"byte_end":784,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":787,"byte_end":795,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":778,"byte_end":784,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types: expected `String`, found `()`
 "}
 {"$message_type":"diagnostic","message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
 "}
diff --git a/tests/ui/json/json-short.stderr b/tests/ui/json/json-short.stderr
index a3d579cadcc..8a4a55edf68 100644
--- a/tests/ui/json/json-short.stderr
+++ b/tests/ui/json/json-short.stderr
@@ -13,7 +13,7 @@ If you don't know the basics of Rust, you can look at the
 [Rust Book][rust-book] to get started.
 
 [rust-book]: https://doc.rust-lang.org/book/
-"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":63,"byte_end":63,"line_start":1,"line_end":1,"column_start":64,"column_end":64,"is_primary":true,"text":[{"text":"//@ compile-flags: --json=diagnostic-short --error-format=json","highlight_start":64,"highlight_end":64}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:1:64: error[E0601]: `main` function not found in crate `json_short`
+"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":63,"byte_end":63,"line_start":1,"line_end":1,"column_start":64,"column_end":64,"is_primary":true,"text":[{"text":"//@ compile-flags: --json=diagnostic-short --error-format=json","highlight_start":64,"highlight_end":64}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:1:64: error[E0601]: `main` function not found in crate `json_short`: consider adding a `main` function to `$DIR/json-short.rs`
 "}
 {"$message_type":"diagnostic","message":"aborting due to 1 previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 1 previous error
 "}
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr
index e446345aedc..ebf6f6ca403 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.stderr
+++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr
@@ -72,3 +72,14 @@ error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0106, E0214, E0308, E0770.
 For more information about an error, try `rustc --explain E0106`.
+Future incompatibility report: Future breakage diagnostic:
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/unusual-rib-combinations.rs:15:6
+   |
+LL | fn c<T = u8()>() {}
+   |      ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
diff --git a/tests/ui/lint/command-line-lint-group-forbid.stderr b/tests/ui/lint/command-line-lint-group-forbid.stderr
index 7b527e7b8b4..ec9b6ca9664 100644
--- a/tests/ui/lint/command-line-lint-group-forbid.stderr
+++ b/tests/ui/lint/command-line-lint-group-forbid.stderr
@@ -5,7 +5,6 @@ LL |     let _InappropriateCamelCasing = true;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `_inappropriate_camel_casing`
    |
    = note: `-F non-snake-case` implied by `-F bad-style`
-   = help: to override `-F bad-style` add `#[allow(non_snake_case)]`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs b/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs
deleted file mode 100644
index 8cd1524045b..00000000000
--- a/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-//@ check-pass
-
-mod ffi {
-    use super::*;
-
-    extern "C" {
-        pub fn DomPromise_AddRef(promise: *const Promise);
-        pub fn DomPromise_Release(promise: *const Promise);
-    }
-}
-
-#[repr(C)]
-#[allow(unused)]
-pub struct Promise {
-    private: [u8; 0],
-    __nosync: ::std::marker::PhantomData<::std::rc::Rc<u8>>,
-}
-
-pub unsafe trait RefCounted {
-    unsafe fn addref(&self);
-    unsafe fn release(&self);
-}
-
-unsafe impl RefCounted for Promise {
-    unsafe fn addref(&self) {
-        ffi::DomPromise_AddRef(self)
-    }
-    unsafe fn release(&self) {
-        ffi::DomPromise_Release(self)
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/lint/dead-code/issue-59003.rs b/tests/ui/lint/dead-code/issue-59003.rs
index 319cf2db149..e3dcaca5778 100644
--- a/tests/ui/lint/dead-code/issue-59003.rs
+++ b/tests/ui/lint/dead-code/issue-59003.rs
@@ -4,8 +4,8 @@
 
 #![deny(dead_code)]
 
-#[allow(dead_code)]
 struct Foo {
+    #[allow(dead_code)]
     inner: u32,
 }
 
diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.rs b/tests/ui/lint/dead-code/lint-dead-code-1.rs
index 3386dfa4747..ddcafedf7bc 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-1.rs
+++ b/tests/ui/lint/dead-code/lint-dead-code-1.rs
@@ -46,10 +46,11 @@ struct SemiUsedStruct;
 impl SemiUsedStruct {
     fn la_la_la() {}
 }
-struct StructUsedAsField; //~ ERROR struct `StructUsedAsField` is never constructed
+struct StructUsedAsField;
 pub struct StructUsedInEnum;
 struct StructUsedInGeneric;
-pub struct PubStruct2 { //~ ERROR struct `PubStruct2` is never constructed
+pub struct PubStruct2 {
+    #[allow(dead_code)]
     struct_used_as_field: *const StructUsedAsField
 }
 
diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.stderr b/tests/ui/lint/dead-code/lint-dead-code-1.stderr
index b0163df8855..eb728b5b930 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-1.stderr
+++ b/tests/ui/lint/dead-code/lint-dead-code-1.stderr
@@ -22,26 +22,14 @@ error: struct `PrivStruct` is never constructed
 LL | struct PrivStruct;
    |        ^^^^^^^^^^
 
-error: struct `StructUsedAsField` is never constructed
-  --> $DIR/lint-dead-code-1.rs:49:8
-   |
-LL | struct StructUsedAsField;
-   |        ^^^^^^^^^^^^^^^^^
-
-error: struct `PubStruct2` is never constructed
-  --> $DIR/lint-dead-code-1.rs:52:12
-   |
-LL | pub struct PubStruct2 {
-   |            ^^^^^^^^^^
-
 error: enum `priv_enum` is never used
-  --> $DIR/lint-dead-code-1.rs:63:6
+  --> $DIR/lint-dead-code-1.rs:64:6
    |
 LL | enum priv_enum { foo2, bar2 }
    |      ^^^^^^^^^
 
 error: variant `bar3` is never constructed
-  --> $DIR/lint-dead-code-1.rs:66:5
+  --> $DIR/lint-dead-code-1.rs:67:5
    |
 LL | enum used_enum {
    |      --------- variant in this enum
@@ -50,25 +38,25 @@ LL |     bar3
    |     ^^^^
 
 error: function `priv_fn` is never used
-  --> $DIR/lint-dead-code-1.rs:87:4
+  --> $DIR/lint-dead-code-1.rs:88:4
    |
 LL | fn priv_fn() {
    |    ^^^^^^^
 
 error: function `foo` is never used
-  --> $DIR/lint-dead-code-1.rs:92:4
+  --> $DIR/lint-dead-code-1.rs:93:4
    |
 LL | fn foo() {
    |    ^^^
 
 error: function `bar` is never used
-  --> $DIR/lint-dead-code-1.rs:97:4
+  --> $DIR/lint-dead-code-1.rs:98:4
    |
 LL | fn bar() {
    |    ^^^
 
 error: function `baz` is never used
-  --> $DIR/lint-dead-code-1.rs:101:4
+  --> $DIR/lint-dead-code-1.rs:102:4
    |
 LL | fn baz() -> impl Copy {
    |    ^^^
@@ -79,5 +67,5 @@ error: struct `Bar` is never constructed
 LL |     pub struct Bar;
    |                ^^^
 
-error: aborting due to 12 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs
deleted file mode 100644
index 25777438456..00000000000
--- a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#![deny(dead_code)]
-
-struct Foo(u8); //~ ERROR struct `Foo` is never constructed
-
-enum Bar { //~ ERROR enum `Bar` is never used
-    Var1(u8),
-    Var2(u8),
-}
-
-pub trait Tr1 {
-    fn f1() -> Self;
-}
-
-impl Tr1 for Foo {
-    fn f1() -> Foo {
-        let f = Foo(0);
-        let Foo(tag) = f;
-        Foo(tag)
-    }
-}
-
-impl Tr1 for Bar {
-    fn f1() -> Bar {
-        let b = Bar::Var1(0);
-        let b = if let Bar::Var1(_) = b {
-            Bar::Var1(0)
-        } else {
-            Bar::Var2(0)
-        };
-        match b {
-            Bar::Var1(_) => Bar::Var2(0),
-            Bar::Var2(_) => Bar::Var1(0),
-        }
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr
deleted file mode 100644
index 7c1a4b45977..00000000000
--- a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: struct `Foo` is never constructed
-  --> $DIR/lint-unused-adt-appeared-in-pattern.rs:3:8
-   |
-LL | struct Foo(u8);
-   |        ^^^
-   |
-note: the lint level is defined here
-  --> $DIR/lint-unused-adt-appeared-in-pattern.rs:1:9
-   |
-LL | #![deny(dead_code)]
-   |         ^^^^^^^^^
-
-error: enum `Bar` is never used
-  --> $DIR/lint-unused-adt-appeared-in-pattern.rs:5:6
-   |
-LL | enum Bar {
-   |      ^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs
deleted file mode 100644
index 43a2e431904..00000000000
--- a/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//@ check-pass
-
-#![deny(dead_code)]
-
-#[repr(u8)]
-#[derive(Copy, Clone, Debug)]
-pub enum RecordField {
-    Target = 1,
-    Level,
-    Module,
-    File,
-    Line,
-    NumArgs,
-}
-
-unsafe trait Pod {}
-
-#[repr(transparent)]
-struct RecordFieldWrapper(RecordField);
-
-unsafe impl Pod for RecordFieldWrapper {}
-
-fn try_read<T: Pod>(buf: &[u8]) -> T {
-    unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const T) }
-}
-
-pub fn foo(buf: &[u8]) -> RecordField {
-    let RecordFieldWrapper(tag) = try_read(buf);
-    tag
-}
-
-fn main() {}
diff --git a/tests/ui/lint/dead-code/unconstructible-pub-struct.rs b/tests/ui/lint/dead-code/unconstructible-pub-struct.rs
deleted file mode 100644
index 2202cbb6730..00000000000
--- a/tests/ui/lint/dead-code/unconstructible-pub-struct.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-#![feature(never_type)]
-#![deny(dead_code)]
-
-pub struct T1(!);
-pub struct T2(());
-pub struct T3<X>(std::marker::PhantomData<X>);
-
-pub struct T4 {
-    _x: !,
-}
-
-pub struct T5<X> {
-    _x: !,
-    _y: X,
-}
-
-pub struct T6 {
-    _x: (),
-}
-
-pub struct T7<X> {
-    _x: (),
-    _y: X,
-}
-
-pub struct T8<X> {
-    _x: std::marker::PhantomData<X>,
-}
-
-pub struct T9<X> { //~ ERROR struct `T9` is never constructed
-    _x: std::marker::PhantomData<X>,
-    _y: i32,
-}
-
-fn main() {}
diff --git a/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr b/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr
deleted file mode 100644
index a3dde042bbe..00000000000
--- a/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: struct `T9` is never constructed
-  --> $DIR/unconstructible-pub-struct.rs:30:12
-   |
-LL | pub struct T9<X> {
-   |            ^^
-   |
-note: the lint level is defined here
-  --> $DIR/unconstructible-pub-struct.rs:2:9
-   |
-LL | #![deny(dead_code)]
-   |         ^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs
index 658cc3d6c61..5b755d62a05 100644
--- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs
+++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs
@@ -1,9 +1,8 @@
 #![deny(dead_code)]
 
 struct T1; //~ ERROR struct `T1` is never constructed
-struct T2; //~ ERROR struct `T2` is never constructed
-pub struct T3(i32); //~ ERROR struct `T3` is never constructed
-pub struct T4(i32); //~ ERROR field `0` is never read
+pub struct T2(i32); //~ ERROR field `0` is never read
+struct T3;
 
 trait Trait1 { //~ ERROR trait `Trait1` is never used
     const UNUSED: i32;
@@ -12,13 +11,13 @@ trait Trait1 { //~ ERROR trait `Trait1` is never used
 }
 
 pub trait Trait2 {
-    const MAY_USED: i32;
-    fn may_used(&self) {}
+    const USED: i32;
+    fn used(&self) {}
 }
 
 pub trait Trait3 {
-    const MAY_USED: i32;
-    fn may_used() -> Self;
+    const USED: i32;
+    fn construct_self() -> Self;
 }
 
 impl Trait1 for T1 {
@@ -31,34 +30,23 @@ impl Trait1 for T1 {
 impl Trait1 for T2 {
     const UNUSED: i32 = 0;
     fn construct_self() -> Self {
-        Self
+        T2(0)
     }
 }
 
 impl Trait2 for T1 {
-    const MAY_USED: i32 = 0;
+    const USED: i32 = 0;
 }
 
 impl Trait2 for T2 {
-    const MAY_USED: i32 = 0;
-}
-
-impl Trait2 for T3 {
-    const MAY_USED: i32 = 0;
+    const USED: i32 = 0;
 }
 
-impl Trait3 for T2 {
-    const MAY_USED: i32 = 0;
-    fn may_used() -> Self {
+impl Trait3 for T3 {
+    const USED: i32 = 0;
+    fn construct_self() -> Self {
         Self
     }
 }
 
-impl Trait3 for T4 {
-    const MAY_USED: i32 = 0;
-    fn may_used() -> Self {
-        T4(0)
-    }
-}
-
 fn main() {}
diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr
index 08c7a5cb4b0..2441a3f868d 100644
--- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr
+++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr
@@ -10,22 +10,10 @@ note: the lint level is defined here
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
 
-error: struct `T2` is never constructed
-  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:8
-   |
-LL | struct T2;
-   |        ^^
-
-error: struct `T3` is never constructed
-  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:5:12
-   |
-LL | pub struct T3(i32);
-   |            ^^
-
 error: field `0` is never read
-  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:6:15
+  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:15
    |
-LL | pub struct T4(i32);
+LL | pub struct T2(i32);
    |            -- ^^^
    |            |
    |            field in this struct
@@ -33,10 +21,10 @@ LL | pub struct T4(i32);
    = help: consider removing this field
 
 error: trait `Trait1` is never used
-  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:8:7
+  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7
    |
 LL | trait Trait1 {
    |       ^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/lint/dead-code/unused-assoc-const.rs b/tests/ui/lint/dead-code/unused-assoc-const.rs
deleted file mode 100644
index 36e8315ad36..00000000000
--- a/tests/ui/lint/dead-code/unused-assoc-const.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#![deny(dead_code)]
-
-trait Trait {
-    const UNUSED_CONST: i32; //~ ERROR associated constant `UNUSED_CONST` is never used
-    const USED_CONST: i32;
-
-    fn foo(&self) {}
-}
-
-pub struct T(());
-
-impl Trait for T {
-    const UNUSED_CONST: i32 = 0;
-    const USED_CONST: i32 = 1;
-}
-
-fn main() {
-    T(()).foo();
-    T::USED_CONST;
-}
diff --git a/tests/ui/lint/dead-code/unused-assoc-const.stderr b/tests/ui/lint/dead-code/unused-assoc-const.stderr
deleted file mode 100644
index 78296d70663..00000000000
--- a/tests/ui/lint/dead-code/unused-assoc-const.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error: associated constant `UNUSED_CONST` is never used
-  --> $DIR/unused-assoc-const.rs:4:11
-   |
-LL | trait Trait {
-   |       ----- associated constant in this trait
-LL |     const UNUSED_CONST: i32;
-   |           ^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/unused-assoc-const.rs:1:9
-   |
-LL | #![deny(dead_code)]
-   |         ^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs b/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs
deleted file mode 100644
index 46065dcee81..00000000000
--- a/tests/ui/lint/dead-code/unused-impl-for-non-adts.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#![deny(dead_code)]
-
-struct Foo; //~ ERROR struct `Foo` is never constructed
-
-trait Trait { //~ ERROR trait `Trait` is never used
-    fn foo(&self) {}
-}
-
-impl Trait for Foo {}
-
-impl Trait for [Foo] {}
-impl<const N: usize> Trait for [Foo; N] {}
-
-impl Trait for *const Foo {}
-impl Trait for *mut Foo {}
-
-impl Trait for &Foo {}
-impl Trait for &&Foo {}
-impl Trait for &mut Foo {}
-
-impl Trait for [&Foo] {}
-impl Trait for &[Foo] {}
-impl Trait for &*const Foo {}
-
-pub trait Trait2 {
-    fn foo(&self) {}
-}
-
-impl Trait2 for Foo {}
-
-impl Trait2 for [Foo] {}
-impl<const N: usize> Trait2 for [Foo; N] {}
-
-impl Trait2 for *const Foo {}
-impl Trait2 for *mut Foo {}
-
-impl Trait2 for &Foo {}
-impl Trait2 for &&Foo {}
-impl Trait2 for &mut Foo {}
-
-impl Trait2 for [&Foo] {}
-impl Trait2 for &[Foo] {}
-impl Trait2 for &*const Foo {}
-
-fn main() {}
diff --git a/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr b/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr
deleted file mode 100644
index e61fc403e81..00000000000
--- a/tests/ui/lint/dead-code/unused-impl-for-non-adts.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: struct `Foo` is never constructed
-  --> $DIR/unused-impl-for-non-adts.rs:3:8
-   |
-LL | struct Foo;
-   |        ^^^
-   |
-note: the lint level is defined here
-  --> $DIR/unused-impl-for-non-adts.rs:1:9
-   |
-LL | #![deny(dead_code)]
-   |         ^^^^^^^^^
-
-error: trait `Trait` is never used
-  --> $DIR/unused-impl-for-non-adts.rs:5:7
-   |
-LL | trait Trait {
-   |       ^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/lint/dead-code/unused-pub-struct.rs b/tests/ui/lint/dead-code/unused-pub-struct.rs
deleted file mode 100644
index aaf4dd612de..00000000000
--- a/tests/ui/lint/dead-code/unused-pub-struct.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-#![deny(dead_code)]
-
-pub struct NotLint1(());
-pub struct NotLint2(std::marker::PhantomData<i32>);
-
-pub struct NeverConstructed(i32); //~ ERROR struct `NeverConstructed` is never constructed
-
-impl NeverConstructed {
-    pub fn not_construct_self(&self) {}
-}
-
-impl Clone for NeverConstructed {
-    fn clone(&self) -> NeverConstructed {
-        NeverConstructed(0)
-    }
-}
-
-pub trait Trait {
-    fn not_construct_self(&self);
-}
-
-impl Trait for NeverConstructed {
-    fn not_construct_self(&self) {
-        self.0;
-    }
-}
-
-pub struct Constructed(i32);
-
-impl Constructed {
-    pub fn construct_self() -> Self {
-        Constructed(0)
-    }
-}
-
-impl Clone for Constructed {
-    fn clone(&self) -> Constructed {
-        Constructed(0)
-    }
-}
-
-impl Trait for Constructed {
-    fn not_construct_self(&self) {
-        self.0;
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/lint/dead-code/unused-pub-struct.stderr b/tests/ui/lint/dead-code/unused-pub-struct.stderr
deleted file mode 100644
index 3667ddb97bd..00000000000
--- a/tests/ui/lint/dead-code/unused-pub-struct.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: struct `NeverConstructed` is never constructed
-  --> $DIR/unused-pub-struct.rs:6:12
-   |
-LL | pub struct NeverConstructed(i32);
-   |            ^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/unused-pub-struct.rs:1:9
-   |
-LL | #![deny(dead_code)]
-   |         ^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.rs b/tests/ui/lint/dead-code/unused-struct-derive-default.rs
index f20b7cb66ee..330ad32dd57 100644
--- a/tests/ui/lint/dead-code/unused-struct-derive-default.rs
+++ b/tests/ui/lint/dead-code/unused-struct-derive-default.rs
@@ -22,5 +22,4 @@ pub struct T2 {
 
 fn main() {
     let _x: Used = Default::default();
-    let _e: E = Default::default();
 }
diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr
index 7422f9a39f3..bbb0bd7be70 100644
--- a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr
+++ b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr
@@ -4,6 +4,7 @@ error: struct `T` is never constructed
 LL | struct T;
    |        ^
    |
+   = note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis
 note: the lint level is defined here
   --> $DIR/unused-struct-derive-default.rs:1:9
    |
diff --git a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs
deleted file mode 100644
index e8116d83ebf..00000000000
--- a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![deny(dead_code)]
-
-struct T1; //~ ERROR struct `T1` is never constructed
-
-trait Foo { type Unused; } //~ ERROR trait `Foo` is never used
-impl Foo for T1 { type Unused = Self; }
-
-pub trait Bar { type Used; }
-impl Bar for T1 { type Used = Self; }
-
-fn main() {}
diff --git a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr
deleted file mode 100644
index ab73c640634..00000000000
--- a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: struct `T1` is never constructed
-  --> $DIR/unused-trait-with-assoc-ty.rs:3:8
-   |
-LL | struct T1;
-   |        ^^
-   |
-note: the lint level is defined here
-  --> $DIR/unused-trait-with-assoc-ty.rs:1:9
-   |
-LL | #![deny(dead_code)]
-   |         ^^^^^^^^^
-
-error: trait `Foo` is never used
-  --> $DIR/unused-trait-with-assoc-ty.rs:5:7
-   |
-LL | trait Foo { type Unused; }
-   |       ^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr
index 01c2ed84c63..d1b764b3414 100644
--- a/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/cap-lints-warn-allowed-warn-by-default-lint.stderr
@@ -7,7 +7,6 @@ LL |         0...100 => true,
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `--force-warn ellipsis-inclusive-range-patterns` implied by `--force-warn rust-2021-compatibility`
-   = help: to override `--force-warn rust-2021-compatibility` add `#[allow(ellipsis_inclusive_range_patterns)]`
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/lint/force-warn/lint-group-allow-warnings.stderr b/tests/ui/lint/force-warn/lint-group-allow-warnings.stderr
index e925a195fb1..dc7b1b7b98d 100644
--- a/tests/ui/lint/force-warn/lint-group-allow-warnings.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allow-warnings.stderr
@@ -5,7 +5,6 @@ LL | pub fn FUNCTION() {}
    |        ^^^^^^^^ help: convert the identifier to snake case: `function`
    |
    = note: `--force-warn non-snake-case` implied by `--force-warn nonstandard-style`
-   = help: to override `--force-warn nonstandard-style` add `#[allow(non_snake_case)]`
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
index a74cda2239f..dc85e8cf961 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
@@ -7,7 +7,6 @@ LL | pub fn function(_x: Box<SomeTrait>) {}
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
-   = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]`
 help: if this is an object-safe trait, use `dyn`
    |
 LL | pub fn function(_x: Box<dyn SomeTrait>) {}
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
index c9472a3b9b9..55cfad838f8 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
@@ -7,7 +7,6 @@ LL | pub fn function(_x: Box<SomeTrait>) {}
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
-   = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]`
 help: if this is an object-safe trait, use `dyn`
    |
 LL | pub fn function(_x: Box<dyn SomeTrait>) {}
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
index 558d5cbb531..b7bf0c4ee21 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
@@ -7,7 +7,6 @@ LL | pub fn function(_x: Box<SomeTrait>) {}
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
-   = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]`
 help: if this is an object-safe trait, use `dyn`
    |
 LL | pub fn function(_x: Box<dyn SomeTrait>) {}
diff --git a/tests/ui/lint/group-forbid-always-trumps-cli.stderr b/tests/ui/lint/group-forbid-always-trumps-cli.stderr
index 21674ebae9c..ed1242eacfc 100644
--- a/tests/ui/lint/group-forbid-always-trumps-cli.stderr
+++ b/tests/ui/lint/group-forbid-always-trumps-cli.stderr
@@ -5,7 +5,6 @@ LL |     let x = 1;
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
    |
    = note: `-F unused-variables` implied by `-F unused`
-   = help: to override `-F unused` add `#[allow(unused_variables)]`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lint/lint-unnecessary-parens.fixed b/tests/ui/lint/lint-unnecessary-parens.fixed
index 760897c5143..089aa1b7ab7 100644
--- a/tests/ui/lint/lint-unnecessary-parens.fixed
+++ b/tests/ui/lint/lint-unnecessary-parens.fixed
@@ -1,6 +1,7 @@
 //@ run-rustfix
 
 #![deny(unused_parens)]
+#![feature(raw_ref_op)]
 #![allow(while_true)] // for rustfix
 
 #[derive(Eq, PartialEq)]
@@ -125,4 +126,11 @@ fn main() {
         // FIXME: false positive. This parenthesis is required.
         unit! {} - One //~ ERROR unnecessary parentheses around block return value
     };
+
+    // Do *not* lint around `&raw` (but do lint when `&` creates a reference).
+    let mut x = 0;
+    let _r = &x; //~ ERROR unnecessary parentheses
+    let _r = &mut x; //~ ERROR unnecessary parentheses
+    let _r = (&raw const x);
+    let _r = (&raw mut x);
 }
diff --git a/tests/ui/lint/lint-unnecessary-parens.rs b/tests/ui/lint/lint-unnecessary-parens.rs
index 7cbaac8ae54..dc77ee00352 100644
--- a/tests/ui/lint/lint-unnecessary-parens.rs
+++ b/tests/ui/lint/lint-unnecessary-parens.rs
@@ -1,6 +1,7 @@
 //@ run-rustfix
 
 #![deny(unused_parens)]
+#![feature(raw_ref_op)]
 #![allow(while_true)] // for rustfix
 
 #[derive(Eq, PartialEq)]
@@ -125,4 +126,11 @@ fn main() {
         // FIXME: false positive. This parenthesis is required.
         (unit! {} - One) //~ ERROR unnecessary parentheses around block return value
     };
+
+    // Do *not* lint around `&raw` (but do lint when `&` creates a reference).
+    let mut x = 0;
+    let _r = (&x); //~ ERROR unnecessary parentheses
+    let _r = (&mut x); //~ ERROR unnecessary parentheses
+    let _r = (&raw const x);
+    let _r = (&raw mut x);
 }
diff --git a/tests/ui/lint/lint-unnecessary-parens.stderr b/tests/ui/lint/lint-unnecessary-parens.stderr
index 755dd5fc309..c9422437a9f 100644
--- a/tests/ui/lint/lint-unnecessary-parens.stderr
+++ b/tests/ui/lint/lint-unnecessary-parens.stderr
@@ -1,5 +1,5 @@
 error: unnecessary parentheses around `return` value
-  --> $DIR/lint-unnecessary-parens.rs:13:12
+  --> $DIR/lint-unnecessary-parens.rs:14:12
    |
 LL |     return (1);
    |            ^ ^
@@ -16,7 +16,7 @@ LL +     return 1;
    |
 
 error: unnecessary parentheses around `return` value
-  --> $DIR/lint-unnecessary-parens.rs:16:12
+  --> $DIR/lint-unnecessary-parens.rs:17:12
    |
 LL |     return (X { y });
    |            ^       ^
@@ -28,7 +28,7 @@ LL +     return X { y };
    |
 
 error: unnecessary parentheses around type
-  --> $DIR/lint-unnecessary-parens.rs:19:46
+  --> $DIR/lint-unnecessary-parens.rs:20:46
    |
 LL | pub fn unused_parens_around_return_type() -> (u32) {
    |                                              ^   ^
@@ -40,7 +40,7 @@ LL + pub fn unused_parens_around_return_type() -> u32 {
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:25:9
+  --> $DIR/lint-unnecessary-parens.rs:26:9
    |
 LL |         (5)
    |         ^ ^
@@ -52,7 +52,7 @@ LL +         5
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:27:5
+  --> $DIR/lint-unnecessary-parens.rs:28:5
    |
 LL |     (5)
    |     ^ ^
@@ -64,7 +64,7 @@ LL +     5
    |
 
 error: unnecessary parentheses around `if` condition
-  --> $DIR/lint-unnecessary-parens.rs:39:7
+  --> $DIR/lint-unnecessary-parens.rs:40:7
    |
 LL |     if(true) {}
    |       ^    ^
@@ -76,7 +76,7 @@ LL +     if true {}
    |
 
 error: unnecessary parentheses around `while` condition
-  --> $DIR/lint-unnecessary-parens.rs:40:10
+  --> $DIR/lint-unnecessary-parens.rs:41:10
    |
 LL |     while(true) {}
    |          ^    ^
@@ -88,7 +88,7 @@ LL +     while true {}
    |
 
 error: unnecessary parentheses around `for` iterator expression
-  --> $DIR/lint-unnecessary-parens.rs:41:13
+  --> $DIR/lint-unnecessary-parens.rs:42:13
    |
 LL |     for _ in(e) {}
    |             ^ ^
@@ -100,7 +100,7 @@ LL +     for _ in e {}
    |
 
 error: unnecessary parentheses around `match` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:42:10
+  --> $DIR/lint-unnecessary-parens.rs:43:10
    |
 LL |     match(1) { _ => ()}
    |          ^ ^
@@ -112,7 +112,7 @@ LL +     match 1 { _ => ()}
    |
 
 error: unnecessary parentheses around `return` value
-  --> $DIR/lint-unnecessary-parens.rs:43:11
+  --> $DIR/lint-unnecessary-parens.rs:44:11
    |
 LL |     return(1);
    |           ^ ^
@@ -124,7 +124,7 @@ LL +     return 1;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:74:31
+  --> $DIR/lint-unnecessary-parens.rs:75:31
    |
 LL | pub const CONST_ITEM: usize = (10);
    |                               ^  ^
@@ -136,7 +136,7 @@ LL + pub const CONST_ITEM: usize = 10;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:75:33
+  --> $DIR/lint-unnecessary-parens.rs:76:33
    |
 LL | pub static STATIC_ITEM: usize = (10);
    |                                 ^  ^
@@ -148,7 +148,7 @@ LL + pub static STATIC_ITEM: usize = 10;
    |
 
 error: unnecessary parentheses around function argument
-  --> $DIR/lint-unnecessary-parens.rs:79:9
+  --> $DIR/lint-unnecessary-parens.rs:80:9
    |
 LL |     bar((true));
    |         ^    ^
@@ -160,7 +160,7 @@ LL +     bar(true);
    |
 
 error: unnecessary parentheses around `if` condition
-  --> $DIR/lint-unnecessary-parens.rs:81:8
+  --> $DIR/lint-unnecessary-parens.rs:82:8
    |
 LL |     if (true) {}
    |        ^    ^
@@ -172,7 +172,7 @@ LL +     if true {}
    |
 
 error: unnecessary parentheses around `while` condition
-  --> $DIR/lint-unnecessary-parens.rs:82:11
+  --> $DIR/lint-unnecessary-parens.rs:83:11
    |
 LL |     while (true) {}
    |           ^    ^
@@ -184,7 +184,7 @@ LL +     while true {}
    |
 
 error: unnecessary parentheses around `match` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:83:11
+  --> $DIR/lint-unnecessary-parens.rs:84:11
    |
 LL |     match (true) {
    |           ^    ^
@@ -196,7 +196,7 @@ LL +     match true {
    |
 
 error: unnecessary parentheses around `let` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:86:16
+  --> $DIR/lint-unnecessary-parens.rs:87:16
    |
 LL |     if let 1 = (1) {}
    |                ^ ^
@@ -208,7 +208,7 @@ LL +     if let 1 = 1 {}
    |
 
 error: unnecessary parentheses around `let` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:87:19
+  --> $DIR/lint-unnecessary-parens.rs:88:19
    |
 LL |     while let 1 = (2) {}
    |                   ^ ^
@@ -220,7 +220,7 @@ LL +     while let 1 = 2 {}
    |
 
 error: unnecessary parentheses around method argument
-  --> $DIR/lint-unnecessary-parens.rs:103:24
+  --> $DIR/lint-unnecessary-parens.rs:104:24
    |
 LL |     X { y: false }.foo((true));
    |                        ^    ^
@@ -232,7 +232,7 @@ LL +     X { y: false }.foo(true);
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:105:18
+  --> $DIR/lint-unnecessary-parens.rs:106:18
    |
 LL |     let mut _a = (0);
    |                  ^ ^
@@ -244,7 +244,7 @@ LL +     let mut _a = 0;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:106:10
+  --> $DIR/lint-unnecessary-parens.rs:107:10
    |
 LL |     _a = (0);
    |          ^ ^
@@ -256,7 +256,7 @@ LL +     _a = 0;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:107:11
+  --> $DIR/lint-unnecessary-parens.rs:108:11
    |
 LL |     _a += (1);
    |           ^ ^
@@ -268,7 +268,7 @@ LL +     _a += 1;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:109:8
+  --> $DIR/lint-unnecessary-parens.rs:110:8
    |
 LL |     let(mut _a) = 3;
    |        ^      ^
@@ -280,7 +280,7 @@ LL +     let mut _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:110:9
+  --> $DIR/lint-unnecessary-parens.rs:111:9
    |
 LL |     let (mut _a) = 3;
    |         ^      ^
@@ -292,7 +292,7 @@ LL +     let mut _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:111:8
+  --> $DIR/lint-unnecessary-parens.rs:112:8
    |
 LL |     let( mut _a) = 3;
    |        ^^      ^
@@ -304,7 +304,7 @@ LL +     let mut _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:113:8
+  --> $DIR/lint-unnecessary-parens.rs:114:8
    |
 LL |     let(_a) = 3;
    |        ^  ^
@@ -316,7 +316,7 @@ LL +     let _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:114:9
+  --> $DIR/lint-unnecessary-parens.rs:115:9
    |
 LL |     let (_a) = 3;
    |         ^  ^
@@ -328,7 +328,7 @@ LL +     let _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:115:8
+  --> $DIR/lint-unnecessary-parens.rs:116:8
    |
 LL |     let( _a) = 3;
    |        ^^  ^
@@ -340,7 +340,7 @@ LL +     let _a = 3;
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:121:9
+  --> $DIR/lint-unnecessary-parens.rs:122:9
    |
 LL |         (unit!() - One)
    |         ^             ^
@@ -352,7 +352,7 @@ LL +         unit!() - One
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:123:9
+  --> $DIR/lint-unnecessary-parens.rs:124:9
    |
 LL |         (unit![] - One)
    |         ^             ^
@@ -364,7 +364,7 @@ LL +         unit![] - One
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:126:9
+  --> $DIR/lint-unnecessary-parens.rs:127:9
    |
 LL |         (unit! {} - One)
    |         ^              ^
@@ -375,5 +375,29 @@ LL -         (unit! {} - One)
 LL +         unit! {} - One
    |
 
-error: aborting due to 31 previous errors
+error: unnecessary parentheses around assigned value
+  --> $DIR/lint-unnecessary-parens.rs:132:14
+   |
+LL |     let _r = (&x);
+   |              ^  ^
+   |
+help: remove these parentheses
+   |
+LL -     let _r = (&x);
+LL +     let _r = &x;
+   |
+
+error: unnecessary parentheses around assigned value
+  --> $DIR/lint-unnecessary-parens.rs:133:14
+   |
+LL |     let _r = (&mut x);
+   |              ^      ^
+   |
+help: remove these parentheses
+   |
+LL -     let _r = (&mut x);
+LL +     let _r = &mut x;
+   |
+
+error: aborting due to 33 previous errors
 
diff --git a/tests/ui/lint/unaligned_references.stderr b/tests/ui/lint/unaligned_references.current.stderr
index 328cafbd986..0f980c5301f 100644
--- a/tests/ui/lint/unaligned_references.stderr
+++ b/tests/ui/lint/unaligned_references.current.stderr
@@ -1,5 +1,5 @@
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:28:13
+  --> $DIR/unaligned_references.rs:32:13
    |
 LL |             &self.x;
    |             ^^^^^^^
@@ -9,7 +9,7 @@ LL |             &self.x;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:40:24
+  --> $DIR/unaligned_references.rs:44:24
    |
 LL |     println!("{:?}", &*foo.0);
    |                        ^^^^^
@@ -19,7 +19,7 @@ LL |     println!("{:?}", &*foo.0);
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:42:24
+  --> $DIR/unaligned_references.rs:46:24
    |
 LL |     println!("{:?}", &*foo.0);
    |                        ^^^^^
@@ -29,7 +29,7 @@ LL |     println!("{:?}", &*foo.0);
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:47:24
+  --> $DIR/unaligned_references.rs:51:24
    |
 LL |     println!("{:?}", &*foo.0);
    |                        ^^^^^
@@ -39,7 +39,7 @@ LL |     println!("{:?}", &*foo.0);
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:57:17
+  --> $DIR/unaligned_references.rs:81:17
    |
 LL |         let _ = &good.ptr;
    |                 ^^^^^^^^^
@@ -49,7 +49,7 @@ LL |         let _ = &good.ptr;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:58:17
+  --> $DIR/unaligned_references.rs:82:17
    |
 LL |         let _ = &good.data;
    |                 ^^^^^^^^^^
@@ -59,7 +59,7 @@ LL |         let _ = &good.data;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:60:17
+  --> $DIR/unaligned_references.rs:84:17
    |
 LL |         let _ = &good.data as *const _;
    |                 ^^^^^^^^^^
@@ -69,7 +69,7 @@ LL |         let _ = &good.data as *const _;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:61:27
+  --> $DIR/unaligned_references.rs:85:27
    |
 LL |         let _: *const _ = &good.data;
    |                           ^^^^^^^^^^
@@ -79,7 +79,7 @@ LL |         let _: *const _ = &good.data;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:63:17
+  --> $DIR/unaligned_references.rs:87:17
    |
 LL |         let _ = good.data.clone();
    |                 ^^^^^^^^^
@@ -89,7 +89,7 @@ LL |         let _ = good.data.clone();
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:65:17
+  --> $DIR/unaligned_references.rs:89:17
    |
 LL |         let _ = &good.data2[0];
    |                 ^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL |         let _ = &good.data2[0];
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:74:17
+  --> $DIR/unaligned_references.rs:98:17
    |
 LL |         let _ = &packed2.x;
    |                 ^^^^^^^^^^
@@ -109,7 +109,7 @@ LL |         let _ = &packed2.x;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:113:20
+  --> $DIR/unaligned_references.rs:137:20
    |
 LL |         let _ref = &m1.1.a;
    |                    ^^^^^^^
@@ -119,7 +119,7 @@ LL |         let _ref = &m1.1.a;
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0793]: reference to packed field is unaligned
-  --> $DIR/unaligned_references.rs:116:20
+  --> $DIR/unaligned_references.rs:140:20
    |
 LL |         let _ref = &m2.1.a;
    |                    ^^^^^^^
diff --git a/tests/ui/lint/unaligned_references.next.stderr b/tests/ui/lint/unaligned_references.next.stderr
new file mode 100644
index 00000000000..0f980c5301f
--- /dev/null
+++ b/tests/ui/lint/unaligned_references.next.stderr
@@ -0,0 +1,133 @@
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:32:13
+   |
+LL |             &self.x;
+   |             ^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:44:24
+   |
+LL |     println!("{:?}", &*foo.0);
+   |                        ^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:46:24
+   |
+LL |     println!("{:?}", &*foo.0);
+   |                        ^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:51:24
+   |
+LL |     println!("{:?}", &*foo.0);
+   |                        ^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:81:17
+   |
+LL |         let _ = &good.ptr;
+   |                 ^^^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:82:17
+   |
+LL |         let _ = &good.data;
+   |                 ^^^^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:84:17
+   |
+LL |         let _ = &good.data as *const _;
+   |                 ^^^^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:85:27
+   |
+LL |         let _: *const _ = &good.data;
+   |                           ^^^^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:87:17
+   |
+LL |         let _ = good.data.clone();
+   |                 ^^^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:89:17
+   |
+LL |         let _ = &good.data2[0];
+   |                 ^^^^^^^^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:98:17
+   |
+LL |         let _ = &packed2.x;
+   |                 ^^^^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:137:20
+   |
+LL |         let _ref = &m1.1.a;
+   |                    ^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error[E0793]: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:140:20
+   |
+LL |         let _ref = &m2.1.a;
+   |                    ^^^^^^^
+   |
+   = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+   = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0793`.
diff --git a/tests/ui/lint/unaligned_references.rs b/tests/ui/lint/unaligned_references.rs
index 3f6dab35475..321e3ed135c 100644
--- a/tests/ui/lint/unaligned_references.rs
+++ b/tests/ui/lint/unaligned_references.rs
@@ -1,5 +1,9 @@
-use std::mem::ManuallyDrop;
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
 use std::fmt::Debug;
+use std::mem::ManuallyDrop;
 
 #[repr(packed)]
 pub struct Good {
@@ -50,6 +54,26 @@ fn packed_dyn() {
     println!("{:?}", &*foo.0); // no error!
 }
 
+// Test for #115396
+fn packed_slice_behind_alias() {
+    trait Mirror {
+        type Assoc: ?Sized;
+    }
+    impl<T: ?Sized> Mirror for T {
+        type Assoc = T;
+    }
+
+    struct W<T: ?Sized>(<T as Mirror>::Assoc);
+
+    #[repr(packed)]
+    struct Unaligned<T: ?Sized>(ManuallyDrop<W<T>>);
+
+    // Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.`
+    let ref local: Unaligned<[_; 3]> = Unaligned(ManuallyDrop::new(W([3, 5, 8u8])));
+    let foo: &Unaligned<[u8]> = local;
+    let x = &foo.0; // Fine, since the tail of `foo` is `[_]`
+}
+
 fn main() {
     unsafe {
         let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] };
diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs
index 6f2ead70db8..c264fa1c8da 100644
--- a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs
+++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs
@@ -1,4 +1,3 @@
-#![feature(unsafe_extern_blocks)]
 #![deny(unsafe_code)]
 
 #[allow(unsafe_code)]
diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr
index 5439a311256..6d3b064da34 100644
--- a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr
+++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr
@@ -1,5 +1,5 @@
 error: usage of an `unsafe extern` block
-  --> $DIR/unsafe-extern-blocks.rs:9:1
+  --> $DIR/unsafe-extern-blocks.rs:8:1
    |
 LL | / unsafe extern "C" {
 LL | |
@@ -8,7 +8,7 @@ LL | | }
    | |_^
    |
 note: the lint level is defined here
-  --> $DIR/unsafe-extern-blocks.rs:2:9
+  --> $DIR/unsafe-extern-blocks.rs:1:9
    |
 LL | #![deny(unsafe_code)]
    |         ^^^^^^^^^^^
diff --git a/tests/ui/never_type/never-result.rs b/tests/ui/never_type/never-result.rs
index bdd06ec5bd1..98ad1404666 100644
--- a/tests/ui/never_type/never-result.rs
+++ b/tests/ui/never_type/never-result.rs
@@ -2,9 +2,8 @@
 
 #![allow(unused_variables)]
 #![allow(unreachable_code)]
-
+#![allow(unreachable_patterns)]
 // Test that we can extract a ! through pattern matching then use it as several different types.
-
 #![feature(never_type)]
 
 fn main() {
@@ -16,6 +15,6 @@ fn main() {
             let w: i32 = y;
             let e: String = y;
             y
-        },
+        }
     }
 }
diff --git a/tests/ui/offset-of/offset-of-slice-normalized.rs b/tests/ui/offset-of/offset-of-slice-normalized.rs
new file mode 100644
index 00000000000..9d1fd9dd2ee
--- /dev/null
+++ b/tests/ui/offset-of/offset-of-slice-normalized.rs
@@ -0,0 +1,37 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ run-pass
+
+#![feature(offset_of_slice)]
+
+use std::mem::offset_of;
+
+trait Mirror {
+    type Assoc: ?Sized;
+}
+impl<T: ?Sized> Mirror for T {
+    type Assoc = T;
+}
+
+#[repr(C)]
+struct S {
+    a: u8,
+    b: (u8, u8),
+    c: <[i32] as Mirror>::Assoc,
+}
+
+#[repr(C)]
+struct T {
+    x: i8,
+    y: S,
+}
+
+type Tup = (i16, <[i32] as Mirror>::Assoc);
+
+fn main() {
+    assert_eq!(offset_of!(S, c), 4);
+    assert_eq!(offset_of!(T, y), 4);
+    assert_eq!(offset_of!(T, y.c), 8);
+    assert_eq!(offset_of!(Tup, 1), 4);
+}
diff --git a/tests/ui/panics/panic-in-cleanup.run.stderr b/tests/ui/panics/panic-in-cleanup.run.stderr
index e7def11b0e9..3417d4bf1a3 100644
--- a/tests/ui/panics/panic-in-cleanup.run.stderr
+++ b/tests/ui/panics/panic-in-cleanup.run.stderr
@@ -4,6 +4,6 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 thread 'main' panicked at $DIR/panic-in-cleanup.rs:16:9:
 BOOM
 stack backtrace:
-thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL:
+thread 'main' panicked at core/src/panicking.rs:$LINE:$COL:
 panic in a destructor during cleanup
 thread caused non-unwinding panic. aborting.
diff --git a/tests/ui/panics/panic-in-ffi.run.stderr b/tests/ui/panics/panic-in-ffi.run.stderr
index 596355399c8..fc70847ad9a 100644
--- a/tests/ui/panics/panic-in-ffi.run.stderr
+++ b/tests/ui/panics/panic-in-ffi.run.stderr
@@ -1,7 +1,7 @@
 thread 'main' panicked at $DIR/panic-in-ffi.rs:12:5:
 Test
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL:
+thread 'main' panicked at core/src/panicking.rs:$LINE:$COL:
 panic in a function that cannot unwind
 stack backtrace:
 thread caused non-unwinding panic. aborting.
diff --git a/tests/ui/parser/issues/issue-105366.fixed b/tests/ui/parser/issues/issue-105366.fixed
index 95419dc07f2..7157b647524 100644
--- a/tests/ui/parser/issues/issue-105366.fixed
+++ b/tests/ui/parser/issues/issue-105366.fixed
@@ -1,6 +1,5 @@
 //@ run-rustfix
 
-#[allow(dead_code)]
 struct Foo;
 
 impl From<i32> for Foo {
diff --git a/tests/ui/parser/issues/issue-105366.rs b/tests/ui/parser/issues/issue-105366.rs
index 3278b737991..dc3cb8b343d 100644
--- a/tests/ui/parser/issues/issue-105366.rs
+++ b/tests/ui/parser/issues/issue-105366.rs
@@ -1,6 +1,5 @@
 //@ run-rustfix
 
-#[allow(dead_code)]
 struct Foo;
 
 fn From<i32> for Foo {
diff --git a/tests/ui/parser/issues/issue-105366.stderr b/tests/ui/parser/issues/issue-105366.stderr
index 195305a2ec8..18c04dfaf20 100644
--- a/tests/ui/parser/issues/issue-105366.stderr
+++ b/tests/ui/parser/issues/issue-105366.stderr
@@ -1,5 +1,5 @@
 error: you might have meant to write `impl` instead of `fn`
-  --> $DIR/issue-105366.rs:6:1
+  --> $DIR/issue-105366.rs:5:1
    |
 LL | fn From<i32> for Foo {
    | ^^
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed
index e9c89807fa5..a851300a982 100644
--- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed
@@ -1,8 +1,7 @@
 // Regression test for issues #100790 and #106439.
 //@ run-rustfix
 
-#[allow(dead_code)]
-pub struct Example(usize)
+pub struct Example(#[allow(dead_code)] usize)
 where
     (): Sized;
 //~^^^ ERROR where clauses are not allowed before tuple struct bodies
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs
index 3bd0f51ec2c..10f435859f1 100644
--- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs
@@ -1,11 +1,10 @@
 // Regression test for issues #100790 and #106439.
 //@ run-rustfix
 
-#[allow(dead_code)]
 pub struct Example
 where
     (): Sized,
-(usize);
+(#[allow(dead_code)] usize);
 //~^^^ ERROR where clauses are not allowed before tuple struct bodies
 
 struct _Demo
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr
index 77eafa6bea3..ddbf237e866 100644
--- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr
@@ -1,23 +1,23 @@
 error: where clauses are not allowed before tuple struct bodies
-  --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:6:1
+  --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:5:1
    |
 LL |   pub struct Example
    |              ------- while parsing this tuple struct
 LL | / where
 LL | |     (): Sized,
    | |______________^ unexpected where clause
-LL |   (usize);
-   |   ------- the struct body
+LL |   (#[allow(dead_code)] usize);
+   |   --------------------------- the struct body
    |
 help: move the body before the where clause
    |
-LL ~ pub struct Example(usize)
+LL ~ pub struct Example(#[allow(dead_code)] usize)
 LL | where
 LL ~     (): Sized;
    |
 
 error: where clauses are not allowed before tuple struct bodies
-  --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:12:1
+  --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:11:1
    |
 LL |   struct _Demo
    |          ----- while parsing this tuple struct
diff --git a/tests/ui/parser/suggest-remove-compount-assign-let-ice.rs b/tests/ui/parser/suggest-remove-compount-assign-let-ice.rs
new file mode 100644
index 00000000000..1affee5678e
--- /dev/null
+++ b/tests/ui/parser/suggest-remove-compount-assign-let-ice.rs
@@ -0,0 +1,16 @@
+//! Previously we would try to issue a suggestion for `let x <op>= 1`, i.e. a compound assignment
+//! within a `let` binding, to remove the `<op>`. The suggestion code unfortunately incorrectly
+//! assumed that the `<op>` is an exactly-1-byte ASCII character, but this assumption is incorrect
+//! because we also recover Unicode-confusables like `➖=` as `-=`. In this example, the suggestion
+//! code used a `+ BytePos(1)` to calculate the span of the `<op>` codepoint that looks like `-` but
+//! the mult-byte Unicode look-alike would cause the suggested removal span to be inside a
+//! multi-byte codepoint boundary, triggering a codepoint boundary assertion.
+//!
+//! issue: rust-lang/rust#128845
+
+fn main() {
+    // Adapted from #128845 but with irrelevant components removed and simplified.
+    let x ➖= 1;
+    //~^ ERROR unknown start of token: \u{2796}
+    //~| ERROR: can't reassign to an uninitialized variable
+}
diff --git a/tests/ui/parser/suggest-remove-compount-assign-let-ice.stderr b/tests/ui/parser/suggest-remove-compount-assign-let-ice.stderr
new file mode 100644
index 00000000000..59716d69b50
--- /dev/null
+++ b/tests/ui/parser/suggest-remove-compount-assign-let-ice.stderr
@@ -0,0 +1,26 @@
+error: unknown start of token: \u{2796}
+  --> $DIR/suggest-remove-compount-assign-let-ice.rs:13:11
+   |
+LL |     let x ➖= 1;
+   |           ^^
+   |
+help: Unicode character '➖' (Heavy Minus Sign) looks like '-' (Minus/Hyphen), but it is not
+   |
+LL |     let x -= 1;
+   |           ~
+
+error: can't reassign to an uninitialized variable
+  --> $DIR/suggest-remove-compount-assign-let-ice.rs:13:11
+   |
+LL |     let x ➖= 1;
+   |           ^^^
+   |
+   = help: if you meant to overwrite, remove the `let` binding
+help: initialize the variable
+   |
+LL -     let x ➖= 1;
+LL +     let x = 1;
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/unsafe-foreign-mod-2.rs b/tests/ui/parser/unsafe-foreign-mod-2.rs
index 0b63a993c5b..6d339cd9088 100644
--- a/tests/ui/parser/unsafe-foreign-mod-2.rs
+++ b/tests/ui/parser/unsafe-foreign-mod-2.rs
@@ -1,8 +1,6 @@
 extern "C" unsafe {
     //~^ ERROR expected `{`, found keyword `unsafe`
-    //~| ERROR extern block cannot be declared unsafe
     unsafe fn foo();
-    //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
 }
 
 fn main() {}
diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr
index 8bd592b5d43..0625e3362ed 100644
--- a/tests/ui/parser/unsafe-foreign-mod-2.stderr
+++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr
@@ -4,21 +4,5 @@ error: expected `{`, found keyword `unsafe`
 LL | extern "C" unsafe {
    |            ^^^^^^ expected `{`
 
-error: extern block cannot be declared unsafe
-  --> $DIR/unsafe-foreign-mod-2.rs:1:12
-   |
-LL | extern "C" unsafe {
-   |            ^^^^^^
-   |
-   = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
-   = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: items in unadorned `extern` blocks cannot have safety qualifiers
-  --> $DIR/unsafe-foreign-mod-2.rs:4:5
-   |
-LL |     unsafe fn foo();
-   |     ^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/unsafe-foreign-mod.rs b/tests/ui/parser/unsafe-foreign-mod.rs
index eab134a4a4d..623c3bb81e4 100644
--- a/tests/ui/parser/unsafe-foreign-mod.rs
+++ b/tests/ui/parser/unsafe-foreign-mod.rs
@@ -1,5 +1,5 @@
-unsafe extern "C" {
-    //~^ ERROR extern block cannot be declared unsafe
-}
+//@ check-pass
+
+unsafe extern "C" {}
 
 fn main() {}
diff --git a/tests/ui/parser/unsafe-foreign-mod.stderr b/tests/ui/parser/unsafe-foreign-mod.stderr
deleted file mode 100644
index 60b918a89b3..00000000000
--- a/tests/ui/parser/unsafe-foreign-mod.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error: extern block cannot be declared unsafe
-  --> $DIR/unsafe-foreign-mod.rs:1:1
-   |
-LL | unsafe extern "C" {
-   | ^^^^^^
-   |
-   = note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
-   = help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs
index d5c5b68be78..fd1d5fb6c47 100644
--- a/tests/ui/pattern/issue-22546.rs
+++ b/tests/ui/pattern/issue-22546.rs
@@ -15,7 +15,7 @@ impl<T: ::std::fmt::Display> Foo<T> {
     }
 }
 
-trait Tr {
+trait Tr { //~ WARN trait `Tr` is never used
     type U;
 }
 
diff --git a/tests/ui/pattern/issue-22546.stderr b/tests/ui/pattern/issue-22546.stderr
new file mode 100644
index 00000000000..e067a95e422
--- /dev/null
+++ b/tests/ui/pattern/issue-22546.stderr
@@ -0,0 +1,10 @@
+warning: trait `Tr` is never used
+  --> $DIR/issue-22546.rs:18:7
+   |
+LL | trait Tr {
+   |       ^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr
index d6304a0b997..bc74069b3e7 100644
--- a/tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/always-inhabited-union-ref.rs:25:11
+  --> $DIR/always-inhabited-union-ref.rs:24:11
    |
 LL |     match uninhab_ref() {
    |           ^^^^^^^^^^^^^
@@ -14,13 +14,13 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
-  --> $DIR/always-inhabited-union-ref.rs:29:11
+  --> $DIR/always-inhabited-union-ref.rs:28:11
    |
 LL |     match uninhab_union() {
    |           ^^^^^^^^^^^^^^^
    |
 note: `Foo` defined here
-  --> $DIR/always-inhabited-union-ref.rs:12:11
+  --> $DIR/always-inhabited-union-ref.rs:11:11
    |
 LL | pub union Foo {
    |           ^^^
diff --git a/tests/ui/pattern/usefulness/always-inhabited-union-ref.min_exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/always-inhabited-union-ref.normal.stderr
index d6304a0b997..bc74069b3e7 100644
--- a/tests/ui/pattern/usefulness/always-inhabited-union-ref.min_exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/always-inhabited-union-ref.normal.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/always-inhabited-union-ref.rs:25:11
+  --> $DIR/always-inhabited-union-ref.rs:24:11
    |
 LL |     match uninhab_ref() {
    |           ^^^^^^^^^^^^^
@@ -14,13 +14,13 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
-  --> $DIR/always-inhabited-union-ref.rs:29:11
+  --> $DIR/always-inhabited-union-ref.rs:28:11
    |
 LL |     match uninhab_union() {
    |           ^^^^^^^^^^^^^^^
    |
 note: `Foo` defined here
-  --> $DIR/always-inhabited-union-ref.rs:12:11
+  --> $DIR/always-inhabited-union-ref.rs:11:11
    |
 LL | pub union Foo {
    |           ^^^
diff --git a/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs b/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs
index 5088098d0ae..335eff425ab 100644
--- a/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs
+++ b/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs
@@ -1,10 +1,9 @@
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 
 // The precise semantics of inhabitedness with respect to unions and references is currently
 // undecided. This test file currently checks a conservative choice.
 
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 #![allow(dead_code)]
 #![allow(unreachable_code)]
diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr
index 9e700ee55ef..1b65ff7aa57 100644
--- a/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr
@@ -38,7 +38,7 @@ LL |         _ if false => {}
 error[E0005]: refutable pattern in local binding
   --> $DIR/empty-match-check-notes.rs:39:9
    |
-LL |     let None = x;
+LL |     let None = *x;
    |         ^^^^ pattern `Some(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
@@ -47,8 +47,8 @@ LL |     let None = x;
    = note: the matched value is of type `Option<SecretlyUninhabitedForeignStruct>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let None = x { todo!() };
-   |     ++              +++++++++++
+LL |     if let None = *x { todo!() };
+   |     ++               +++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered
   --> $DIR/empty-match-check-notes.rs:49:11
diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr b/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr
index 480ae7095a6..1b65ff7aa57 100644
--- a/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr
@@ -38,16 +38,17 @@ LL |         _ if false => {}
 error[E0005]: refutable pattern in local binding
   --> $DIR/empty-match-check-notes.rs:39:9
    |
-LL |     let None = x;
+LL |     let None = *x;
    |         ^^^^ pattern `Some(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: pattern `Some(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
    = note: the matched value is of type `Option<SecretlyUninhabitedForeignStruct>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let None = x { todo!() };
-   |     ++              +++++++++++
+LL |     if let None = *x { todo!() };
+   |     ++               +++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered
   --> $DIR/empty-match-check-notes.rs:49:11
diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.rs b/tests/ui/pattern/usefulness/empty-match-check-notes.rs
index 2eef283a21e..61a75e6c801 100644
--- a/tests/ui/pattern/usefulness/empty-match-check-notes.rs
+++ b/tests/ui/pattern/usefulness/empty-match-check-notes.rs
@@ -35,14 +35,14 @@ fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
     }
 }
 
-fn empty_foreign_enum_private(x: Option<empty::SecretlyUninhabitedForeignStruct>) {
-    let None = x;
+fn empty_foreign_enum_private(x: &Option<empty::SecretlyUninhabitedForeignStruct>) {
+    let None = *x;
     //~^ ERROR refutable pattern in local binding
     //~| NOTE `let` bindings require an "irrefutable pattern"
     //~| NOTE for more information, visit
     //~| NOTE the matched value is of type
     //~| NOTE pattern `Some(_)` not covered
-    //[exhaustive_patterns]~| NOTE currently uninhabited, but this variant contains private fields
+    //~| NOTE currently uninhabited, but this variant contains private fields
 }
 
 fn main() {
diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
index 5f895fab0fb..f2067f0341f 100644
--- a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/empty-match.rs:46:20
+  --> $DIR/empty-match.rs:47:20
    |
 LL |     match_no_arms!(0u8);
    |                    ^^^
@@ -8,7 +8,7 @@ LL |     match_no_arms!(0u8);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `i8` is non-empty
-  --> $DIR/empty-match.rs:47:20
+  --> $DIR/empty-match.rs:48:20
    |
 LL |     match_no_arms!(0i8);
    |                    ^^^
@@ -17,7 +17,7 @@ LL |     match_no_arms!(0i8);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/empty-match.rs:48:20
+  --> $DIR/empty-match.rs:49:20
    |
 LL |     match_no_arms!(0usize);
    |                    ^^^^^^
@@ -26,7 +26,7 @@ LL |     match_no_arms!(0usize);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `isize` is non-empty
-  --> $DIR/empty-match.rs:49:20
+  --> $DIR/empty-match.rs:50:20
    |
 LL |     match_no_arms!(0isize);
    |                    ^^^^^^
@@ -35,7 +35,7 @@ LL |     match_no_arms!(0isize);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
-  --> $DIR/empty-match.rs:50:20
+  --> $DIR/empty-match.rs:51:20
    |
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     struct NonEmptyStruct1;
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
-  --> $DIR/empty-match.rs:51:20
+  --> $DIR/empty-match.rs:52:20
    |
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |     struct NonEmptyStruct2(bool);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/empty-match.rs:52:20
+  --> $DIR/empty-match.rs:53:20
    |
 LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     union NonEmptyUnion1 {
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/empty-match.rs:53:20
+  --> $DIR/empty-match.rs:54:20
    |
 LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -91,7 +91,7 @@ LL |     union NonEmptyUnion2 {
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:54:20
+  --> $DIR/empty-match.rs:55:20
    |
 LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
@@ -107,7 +107,7 @@ LL |         Foo(bool),
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:55:20
+  --> $DIR/empty-match.rs:56:20
    |
 LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
@@ -125,7 +125,7 @@ LL |         Bar,
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:56:20
+  --> $DIR/empty-match.rs:57:20
    |
 LL |     match_no_arms!(NonEmptyEnum5::V1);
    |                    ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
@@ -148,8 +148,26 @@ LL |         V5,
    = note: the matched value is of type `NonEmptyEnum5`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
+error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
+  --> $DIR/empty-match.rs:58:20
+   |
+LL |     match_no_arms!(array0_of_empty);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `[!; 0]`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `[!; N]` is non-empty
+  --> $DIR/empty-match.rs:59:20
+   |
+LL |     match_no_arms!(arrayN_of_empty);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `[!; N]`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
 error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered
-  --> $DIR/empty-match.rs:58:24
+  --> $DIR/empty-match.rs:61:24
    |
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `0_u8..=u8::MAX` not covered
@@ -163,7 +181,7 @@ LL +                 0_u8..=u8::MAX => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `i8::MIN..=i8::MAX` not covered
-  --> $DIR/empty-match.rs:59:24
+  --> $DIR/empty-match.rs:62:24
    |
 LL |     match_guarded_arm!(0i8);
    |                        ^^^ pattern `i8::MIN..=i8::MAX` not covered
@@ -177,7 +195,7 @@ LL +                 i8::MIN..=i8::MAX => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `0_usize..` not covered
-  --> $DIR/empty-match.rs:60:24
+  --> $DIR/empty-match.rs:63:24
    |
 LL |     match_guarded_arm!(0usize);
    |                        ^^^^^^ pattern `0_usize..` not covered
@@ -191,7 +209,7 @@ LL +                 0_usize.. => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/empty-match.rs:61:24
+  --> $DIR/empty-match.rs:64:24
    |
 LL |     match_guarded_arm!(0isize);
    |                        ^^^^^^ pattern `_` not covered
@@ -205,7 +223,7 @@ LL +                 _ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
-  --> $DIR/empty-match.rs:62:24
+  --> $DIR/empty-match.rs:65:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
@@ -224,7 +242,7 @@ LL +                 NonEmptyStruct1 => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
-  --> $DIR/empty-match.rs:63:24
+  --> $DIR/empty-match.rs:66:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
@@ -243,7 +261,7 @@ LL +                 NonEmptyStruct2(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/empty-match.rs:64:24
+  --> $DIR/empty-match.rs:67:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
@@ -262,7 +280,7 @@ LL +                 NonEmptyUnion1 { .. } => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/empty-match.rs:65:24
+  --> $DIR/empty-match.rs:68:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
@@ -273,6 +291,7 @@ note: `NonEmptyUnion2` defined here
 LL |     union NonEmptyUnion2 {
    |           ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
@@ -281,7 +300,7 @@ LL +                 NonEmptyUnion2 { .. } => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:66:24
+  --> $DIR/empty-match.rs:69:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
@@ -302,7 +321,7 @@ LL +                 NonEmptyEnum1::Foo(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:67:24
+  --> $DIR/empty-match.rs:70:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
@@ -325,7 +344,7 @@ LL +                 NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:68:24
+  --> $DIR/empty-match.rs:71:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum5::V1);
    |                        ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
@@ -353,6 +372,34 @@ LL ~                 _ if false => {},
 LL +                 _ => todo!()
    |
 
-error: aborting due to 22 previous errors
+error[E0004]: non-exhaustive patterns: `[]` not covered
+  --> $DIR/empty-match.rs:72:24
+   |
+LL |     match_guarded_arm!(array0_of_empty);
+   |                        ^^^^^^^^^^^^^^^ pattern `[]` not covered
+   |
+   = note: the matched value is of type `[!; 0]`
+   = note: match arms with guards don't count towards exhaustivity
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~                 _ if false => {},
+LL +                 [] => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `[]` not covered
+  --> $DIR/empty-match.rs:73:24
+   |
+LL |     match_guarded_arm!(arrayN_of_empty);
+   |                        ^^^^^^^^^^^^^^^ pattern `[]` not covered
+   |
+   = note: the matched value is of type `[!; N]`
+   = note: match arms with guards don't count towards exhaustivity
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~                 _ if false => {},
+LL +                 [] => todo!()
+   |
+
+error: aborting due to 26 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr
index 5f895fab0fb..f2067f0341f 100644
--- a/tests/ui/pattern/usefulness/empty-match.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/empty-match.rs:46:20
+  --> $DIR/empty-match.rs:47:20
    |
 LL |     match_no_arms!(0u8);
    |                    ^^^
@@ -8,7 +8,7 @@ LL |     match_no_arms!(0u8);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `i8` is non-empty
-  --> $DIR/empty-match.rs:47:20
+  --> $DIR/empty-match.rs:48:20
    |
 LL |     match_no_arms!(0i8);
    |                    ^^^
@@ -17,7 +17,7 @@ LL |     match_no_arms!(0i8);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/empty-match.rs:48:20
+  --> $DIR/empty-match.rs:49:20
    |
 LL |     match_no_arms!(0usize);
    |                    ^^^^^^
@@ -26,7 +26,7 @@ LL |     match_no_arms!(0usize);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `isize` is non-empty
-  --> $DIR/empty-match.rs:49:20
+  --> $DIR/empty-match.rs:50:20
    |
 LL |     match_no_arms!(0isize);
    |                    ^^^^^^
@@ -35,7 +35,7 @@ LL |     match_no_arms!(0isize);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
-  --> $DIR/empty-match.rs:50:20
+  --> $DIR/empty-match.rs:51:20
    |
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     struct NonEmptyStruct1;
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
-  --> $DIR/empty-match.rs:51:20
+  --> $DIR/empty-match.rs:52:20
    |
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |     struct NonEmptyStruct2(bool);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/empty-match.rs:52:20
+  --> $DIR/empty-match.rs:53:20
    |
 LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     union NonEmptyUnion1 {
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/empty-match.rs:53:20
+  --> $DIR/empty-match.rs:54:20
    |
 LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -91,7 +91,7 @@ LL |     union NonEmptyUnion2 {
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:54:20
+  --> $DIR/empty-match.rs:55:20
    |
 LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
@@ -107,7 +107,7 @@ LL |         Foo(bool),
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:55:20
+  --> $DIR/empty-match.rs:56:20
    |
 LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
@@ -125,7 +125,7 @@ LL |         Bar,
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:56:20
+  --> $DIR/empty-match.rs:57:20
    |
 LL |     match_no_arms!(NonEmptyEnum5::V1);
    |                    ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
@@ -148,8 +148,26 @@ LL |         V5,
    = note: the matched value is of type `NonEmptyEnum5`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
+error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
+  --> $DIR/empty-match.rs:58:20
+   |
+LL |     match_no_arms!(array0_of_empty);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `[!; 0]`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `[!; N]` is non-empty
+  --> $DIR/empty-match.rs:59:20
+   |
+LL |     match_no_arms!(arrayN_of_empty);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `[!; N]`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
 error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered
-  --> $DIR/empty-match.rs:58:24
+  --> $DIR/empty-match.rs:61:24
    |
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `0_u8..=u8::MAX` not covered
@@ -163,7 +181,7 @@ LL +                 0_u8..=u8::MAX => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `i8::MIN..=i8::MAX` not covered
-  --> $DIR/empty-match.rs:59:24
+  --> $DIR/empty-match.rs:62:24
    |
 LL |     match_guarded_arm!(0i8);
    |                        ^^^ pattern `i8::MIN..=i8::MAX` not covered
@@ -177,7 +195,7 @@ LL +                 i8::MIN..=i8::MAX => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `0_usize..` not covered
-  --> $DIR/empty-match.rs:60:24
+  --> $DIR/empty-match.rs:63:24
    |
 LL |     match_guarded_arm!(0usize);
    |                        ^^^^^^ pattern `0_usize..` not covered
@@ -191,7 +209,7 @@ LL +                 0_usize.. => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/empty-match.rs:61:24
+  --> $DIR/empty-match.rs:64:24
    |
 LL |     match_guarded_arm!(0isize);
    |                        ^^^^^^ pattern `_` not covered
@@ -205,7 +223,7 @@ LL +                 _ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
-  --> $DIR/empty-match.rs:62:24
+  --> $DIR/empty-match.rs:65:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
@@ -224,7 +242,7 @@ LL +                 NonEmptyStruct1 => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
-  --> $DIR/empty-match.rs:63:24
+  --> $DIR/empty-match.rs:66:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
@@ -243,7 +261,7 @@ LL +                 NonEmptyStruct2(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/empty-match.rs:64:24
+  --> $DIR/empty-match.rs:67:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
@@ -262,7 +280,7 @@ LL +                 NonEmptyUnion1 { .. } => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/empty-match.rs:65:24
+  --> $DIR/empty-match.rs:68:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
@@ -273,6 +291,7 @@ note: `NonEmptyUnion2` defined here
 LL |     union NonEmptyUnion2 {
    |           ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
@@ -281,7 +300,7 @@ LL +                 NonEmptyUnion2 { .. } => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:66:24
+  --> $DIR/empty-match.rs:69:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
@@ -302,7 +321,7 @@ LL +                 NonEmptyEnum1::Foo(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:67:24
+  --> $DIR/empty-match.rs:70:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
@@ -325,7 +344,7 @@ LL +                 NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:68:24
+  --> $DIR/empty-match.rs:71:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum5::V1);
    |                        ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
@@ -353,6 +372,34 @@ LL ~                 _ if false => {},
 LL +                 _ => todo!()
    |
 
-error: aborting due to 22 previous errors
+error[E0004]: non-exhaustive patterns: `[]` not covered
+  --> $DIR/empty-match.rs:72:24
+   |
+LL |     match_guarded_arm!(array0_of_empty);
+   |                        ^^^^^^^^^^^^^^^ pattern `[]` not covered
+   |
+   = note: the matched value is of type `[!; 0]`
+   = note: match arms with guards don't count towards exhaustivity
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~                 _ if false => {},
+LL +                 [] => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `[]` not covered
+  --> $DIR/empty-match.rs:73:24
+   |
+LL |     match_guarded_arm!(arrayN_of_empty);
+   |                        ^^^^^^^^^^^^^^^ pattern `[]` not covered
+   |
+   = note: the matched value is of type `[!; N]`
+   = note: match arms with guards don't count towards exhaustivity
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~                 _ if false => {},
+LL +                 [] => todo!()
+   |
+
+error: aborting due to 26 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.rs b/tests/ui/pattern/usefulness/empty-match.rs
index 9b22b47a12b..b34427a7c23 100644
--- a/tests/ui/pattern/usefulness/empty-match.rs
+++ b/tests/ui/pattern/usefulness/empty-match.rs
@@ -5,7 +5,7 @@
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
 #![deny(unreachable_patterns)]
 
-fn nonempty() {
+fn nonempty<const N: usize>(arrayN_of_empty: [!; N]) {
     macro_rules! match_no_arms {
         ($e:expr) => {
             match $e {}
@@ -42,6 +42,7 @@ fn nonempty() {
         V4,
         V5,
     }
+    let array0_of_empty: [!; 0] = [];
 
     match_no_arms!(0u8); //~ ERROR type `u8` is non-empty
     match_no_arms!(0i8); //~ ERROR type `i8` is non-empty
@@ -54,6 +55,8 @@ fn nonempty() {
     match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
     match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
     match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+    match_no_arms!(array0_of_empty); //~ ERROR type `[!; 0]` is non-empty
+    match_no_arms!(arrayN_of_empty); //~ ERROR type `[!; N]` is non-empty
 
     match_guarded_arm!(0u8); //~ ERROR `0_u8..=u8::MAX` not covered
     match_guarded_arm!(0i8); //~ ERROR `i8::MIN..=i8::MAX` not covered
@@ -66,6 +69,8 @@ fn nonempty() {
     match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
     match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
     match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+    match_guarded_arm!(array0_of_empty); //~ ERROR `[]` not covered
+    match_guarded_arm!(arrayN_of_empty); //~ ERROR `[]` not covered
 }
 
 fn main() {}
diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
index 416a50b87b5..17cb6fbd94b 100644
--- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/empty-types.rs:51:9
+  --> $DIR/empty-types.rs:49:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 note: the lint level is defined here
-  --> $DIR/empty-types.rs:17:9
+  --> $DIR/empty-types.rs:15:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:54:9
+  --> $DIR/empty-types.rs:52:9
    |
 LL |         _x => {}
    |         ^^
@@ -20,7 +20,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/empty-types.rs:58:11
+  --> $DIR/empty-types.rs:56:11
    |
 LL |     match ref_never {}
    |           ^^^^^^^^^
@@ -35,7 +35,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:73:9
+  --> $DIR/empty-types.rs:70:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -43,7 +43,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(u32, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:80:9
+  --> $DIR/empty-types.rs:76:9
    |
 LL |         _ => {}
    |         ^
@@ -51,7 +51,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:83:9
+  --> $DIR/empty-types.rs:79:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -59,7 +59,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:87:9
+  --> $DIR/empty-types.rs:83:9
    |
 LL |         _ => {}
    |         ^
@@ -67,7 +67,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
-  --> $DIR/empty-types.rs:91:11
+  --> $DIR/empty-types.rs:87:11
    |
 LL |     match res_u32_never {}
    |           ^^^^^^^^^^^^^ pattern `Ok(_)` not covered
@@ -86,7 +86,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:99:9
+  --> $DIR/empty-types.rs:94:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -94,7 +94,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:104:9
+  --> $DIR/empty-types.rs:99:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -102,7 +102,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered
-  --> $DIR/empty-types.rs:101:11
+  --> $DIR/empty-types.rs:96:11
    |
 LL |     match res_u32_never {
    |           ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered
@@ -120,7 +120,7 @@ LL ~         Ok(1_u32..=u32::MAX) => todo!()
    |
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:108:9
+  --> $DIR/empty-types.rs:102:9
    |
 LL |     let Ok(_x) = res_u32_never.as_ref();
    |         ^^^^^^ pattern `Err(_)` not covered
@@ -134,7 +134,7 @@ LL |     let Ok(_x) = res_u32_never.as_ref() else { todo!() };
    |                                         ++++++++++++++++
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:119:9
+  --> $DIR/empty-types.rs:112:9
    |
 LL |         _ => {}
    |         ^
@@ -142,7 +142,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:123:9
+  --> $DIR/empty-types.rs:115:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -150,7 +150,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:126:9
+  --> $DIR/empty-types.rs:118:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -158,7 +158,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:127:9
+  --> $DIR/empty-types.rs:119:9
    |
 LL |         _ => {}
    |         ^
@@ -166,7 +166,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:130:9
+  --> $DIR/empty-types.rs:122:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -174,7 +174,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:131:9
+  --> $DIR/empty-types.rs:123:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -182,7 +182,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:140:13
+  --> $DIR/empty-types.rs:132:13
    |
 LL |             _ => {}
    |             ^
@@ -190,7 +190,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:143:13
+  --> $DIR/empty-types.rs:135:13
    |
 LL |             _ if false => {}
    |             ^
@@ -198,7 +198,7 @@ LL |             _ if false => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:152:13
+  --> $DIR/empty-types.rs:143:13
    |
 LL |             Some(_) => {}
    |             ^^^^^^^
@@ -206,7 +206,7 @@ LL |             Some(_) => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:156:13
+  --> $DIR/empty-types.rs:147:13
    |
 LL |             None => {}
    |             ---- matches all the values already
@@ -214,7 +214,7 @@ LL |             _ => {}
    |             ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:208:13
+  --> $DIR/empty-types.rs:199:13
    |
 LL |             _ => {}
    |             ^
@@ -222,7 +222,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:213:13
+  --> $DIR/empty-types.rs:204:13
    |
 LL |             _ => {}
    |             ^
@@ -230,7 +230,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:218:13
+  --> $DIR/empty-types.rs:209:13
    |
 LL |             _ => {}
    |             ^
@@ -238,7 +238,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:223:13
+  --> $DIR/empty-types.rs:214:13
    |
 LL |             _ => {}
    |             ^
@@ -246,7 +246,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:229:13
+  --> $DIR/empty-types.rs:220:13
    |
 LL |             _ => {}
    |             ^
@@ -254,7 +254,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:288:9
+  --> $DIR/empty-types.rs:279:9
    |
 LL |         _ => {}
    |         ^
@@ -262,7 +262,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:291:9
+  --> $DIR/empty-types.rs:282:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -270,7 +270,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:294:9
+  --> $DIR/empty-types.rs:285:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -278,7 +278,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:295:9
+  --> $DIR/empty-types.rs:286:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -286,7 +286,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:327:11
+  --> $DIR/empty-types.rs:318:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -300,7 +300,7 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` not covered
-  --> $DIR/empty-types.rs:338:11
+  --> $DIR/empty-types.rs:329:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[]` not covered
@@ -313,7 +313,7 @@ LL +         &[] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` not covered
-  --> $DIR/empty-types.rs:352:11
+  --> $DIR/empty-types.rs:343:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[]` not covered
@@ -327,7 +327,7 @@ LL +         &[] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:359:11
+  --> $DIR/empty-types.rs:350:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -341,7 +341,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:369:9
+  --> $DIR/empty-types.rs:359:9
    |
 LL |         _ => {}
    |         ^
@@ -349,7 +349,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:372:9
+  --> $DIR/empty-types.rs:362:9
    |
 LL |         [_, _, _] => {}
    |         ^^^^^^^^^
@@ -357,7 +357,7 @@ LL |         [_, _, _] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:375:9
+  --> $DIR/empty-types.rs:365:9
    |
 LL |         [_, ..] => {}
    |         ^^^^^^^
@@ -365,7 +365,7 @@ LL |         [_, ..] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:389:11
+  --> $DIR/empty-types.rs:379:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -379,7 +379,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:396:9
+  --> $DIR/empty-types.rs:386:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -387,7 +387,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:398:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -401,7 +401,7 @@ LL +         [] => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:417:9
+  --> $DIR/empty-types.rs:407:9
    |
 LL |         Some(_) => {}
    |         ^^^^^^^
@@ -409,7 +409,7 @@ LL |         Some(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:422:9
+  --> $DIR/empty-types.rs:412:9
    |
 LL |         Some(_a) => {}
    |         ^^^^^^^^
@@ -417,7 +417,7 @@ LL |         Some(_a) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:427:9
+  --> $DIR/empty-types.rs:417:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -426,7 +426,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:432:9
+  --> $DIR/empty-types.rs:422:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -435,7 +435,7 @@ LL |         _a => {}
    |         ^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:604:9
+  --> $DIR/empty-types.rs:594:9
    |
 LL |         _ => {}
    |         ^
@@ -443,7 +443,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:607:9
+  --> $DIR/empty-types.rs:597:9
    |
 LL |         _x => {}
    |         ^^
@@ -451,7 +451,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:610:9
+  --> $DIR/empty-types.rs:600:9
    |
 LL |         _ if false => {}
    |         ^
@@ -459,7 +459,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:613:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _x if false => {}
    |         ^^
diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
index 4856a2f8e08..1ecb15f2cae 100644
--- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
@@ -1,5 +1,5 @@
 warning: the feature `never_patterns` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/empty-types.rs:14:33
+  --> $DIR/empty-types.rs:12:33
    |
 LL | #![cfg_attr(never_pats, feature(never_patterns))]
    |                                 ^^^^^^^^^^^^^^
@@ -8,20 +8,20 @@ LL | #![cfg_attr(never_pats, feature(never_patterns))]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:51:9
+  --> $DIR/empty-types.rs:49:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 note: the lint level is defined here
-  --> $DIR/empty-types.rs:17:9
+  --> $DIR/empty-types.rs:15:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:54:9
+  --> $DIR/empty-types.rs:52:9
    |
 LL |         _x => {}
    |         ^^
@@ -29,7 +29,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/empty-types.rs:58:11
+  --> $DIR/empty-types.rs:56:11
    |
 LL |     match ref_never {}
    |           ^^^^^^^^^
@@ -43,84 +43,75 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:70:11
-   |
-LL |     match tuple_half_never {}
-   |           ^^^^^^^^^^^^^^^^
-   |
-   = note: the matched value is of type `(u32, !)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+error: unreachable pattern
+  --> $DIR/empty-types.rs:70:9
    |
-LL ~     match tuple_half_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         (_, _) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `(u32, !)` is uninhabited
 
-error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:77:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:76:9
    |
-LL |     match tuple_never {}
-   |           ^^^^^^^^^^^
+LL |         _ => {}
+   |         ^
    |
-   = note: the matched value is of type `(!, !)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   = note: this pattern matches no values because `(!, !)` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:79:9
    |
-LL ~     match tuple_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         (_, _) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:87:9
+  --> $DIR/empty-types.rs:83:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(!)` not covered
-  --> $DIR/empty-types.rs:91:11
+error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
+  --> $DIR/empty-types.rs:87:11
    |
 LL |     match res_u32_never {}
-   |           ^^^^^^^^^^^^^ patterns `Ok(_)` and `Err(!)` not covered
+   |           ^^^^^^^^^^^^^ pattern `Ok(_)` not covered
    |
 note: `Result<u32, !>` defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
    = note: not covered
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Result<u32, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~     match res_u32_never {
-LL +         Ok(_) | Err(!) => todo!(),
+LL +         Ok(_) => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:93:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:94:9
    |
-LL |     match res_u32_never {
-   |           ^^^^^^^^^^^^^ pattern `Err(!)` not covered
+LL |         Err(_) => {}
+   |         ^^^^^^
    |
-note: `Result<u32, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
-   = note: the matched value is of type `Result<u32, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:99:9
    |
-LL ~         Ok(_) => {},
-LL +         Err(!)
+LL |         Err(_) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered
-  --> $DIR/empty-types.rs:101:11
+  --> $DIR/empty-types.rs:96:11
    |
 LL |     match res_u32_never {
    |           ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered
@@ -138,21 +129,7 @@ LL ~         Ok(1_u32..=u32::MAX) => todo!()
    |
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:106:9
-   |
-LL |     let Ok(_x) = res_u32_never;
-   |         ^^^^^^ pattern `Err(!)` not covered
-   |
-   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `Result<u32, !>`
-help: you might want to use `let else` to handle the variant that isn't matched
-   |
-LL |     let Ok(_x) = res_u32_never else { todo!() };
-   |                                ++++++++++++++++
-
-error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:108:9
+  --> $DIR/empty-types.rs:102:9
    |
 LL |     let Ok(_x) = res_u32_never.as_ref();
    |         ^^^^^^ pattern `Err(_)` not covered
@@ -166,7 +143,7 @@ LL |     let Ok(_x) = res_u32_never.as_ref() else { todo!() };
    |                                         ++++++++++++++++
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:112:9
+  --> $DIR/empty-types.rs:106:9
    |
 LL |     let Ok(_x) = &res_u32_never;
    |         ^^^^^^ pattern `&Err(!)` not covered
@@ -179,47 +156,56 @@ help: you might want to use `let else` to handle the variant that isn't matched
 LL |     let Ok(_x) = &res_u32_never else { todo!() };
    |                                 ++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `Ok(!)` and `Err(!)` not covered
-  --> $DIR/empty-types.rs:116:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:112:9
    |
-LL |     match result_never {}
-   |           ^^^^^^^^^^^^ patterns `Ok(!)` and `Err(!)` not covered
+LL |         _ => {}
+   |         ^
    |
-note: `Result<!, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:115:9
    |
-   = note: not covered
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
-   = note: not covered
-   = note: the matched value is of type `Result<!, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:118:9
    |
-LL ~     match result_never {
-LL +         Ok(!) | Err(!),
-LL +     }
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:121:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:119:9
    |
-LL |     match result_never {
-   |           ^^^^^^^^^^^^ pattern `Err(!)` not covered
+LL |         _ => {}
+   |         ^
    |
-note: `Result<!, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:122:9
    |
-   = note: not covered
-   = note: the matched value is of type `Result<!, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
-LL |         Ok(_) => {}, Err(!)
-   |                    ++++++++
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:140:13
+  --> $DIR/empty-types.rs:123:9
+   |
+LL |         Err(_) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:132:13
    |
 LL |             _ => {}
    |             ^
@@ -227,33 +213,31 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:143:13
+  --> $DIR/empty-types.rs:135:13
    |
 LL |             _ if false => {}
    |             ^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:146:15
-   |
-LL |         match opt_void {
-   |               ^^^^^^^^ pattern `Some(!)` not covered
+error: unreachable pattern
+  --> $DIR/empty-types.rs:143:13
    |
-note: `Option<Void>` defined here
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+LL |             Some(_) => {}
+   |             ^^^^^^^
    |
-   = note: not covered
-   = note: the matched value is of type `Option<Void>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
-   |
-LL ~             None => {},
-LL +             Some(!)
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:147:13
    |
+LL |             None => {}
+   |             ---- matches all the values already
+LL |             _ => {}
+   |             ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:165:15
+  --> $DIR/empty-types.rs:156:15
    |
 LL |         match *ref_opt_void {
    |               ^^^^^^^^^^^^^ pattern `Some(!)` not covered
@@ -264,6 +248,7 @@ note: `Option<Void>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~             None => {},
@@ -271,7 +256,7 @@ LL +             Some(!)
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:208:13
+  --> $DIR/empty-types.rs:199:13
    |
 LL |             _ => {}
    |             ^
@@ -279,7 +264,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:213:13
+  --> $DIR/empty-types.rs:204:13
    |
 LL |             _ => {}
    |             ^
@@ -287,7 +272,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:218:13
+  --> $DIR/empty-types.rs:209:13
    |
 LL |             _ => {}
    |             ^
@@ -295,7 +280,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:223:13
+  --> $DIR/empty-types.rs:214:13
    |
 LL |             _ => {}
    |             ^
@@ -303,7 +288,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:229:13
+  --> $DIR/empty-types.rs:220:13
    |
 LL |             _ => {}
    |             ^
@@ -311,15 +296,39 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:288:9
+  --> $DIR/empty-types.rs:279:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 
+error: unreachable pattern
+  --> $DIR/empty-types.rs:282:9
+   |
+LL |         (_, _) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `(!, !)` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:285:9
+   |
+LL |         Ok(_) => {}
+   |         ^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:286:9
+   |
+LL |         Err(_) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:316:11
+  --> $DIR/empty-types.rs:307:11
    |
 LL |     match *x {}
    |           ^^
@@ -333,7 +342,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:318:11
+  --> $DIR/empty-types.rs:309:11
    |
 LL |     match *x {}
    |           ^^
@@ -347,7 +356,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(!)` and `Err(!)` not covered
-  --> $DIR/empty-types.rs:320:11
+  --> $DIR/empty-types.rs:311:11
    |
 LL |     match *x {}
    |           ^^ patterns `Ok(!)` and `Err(!)` not covered
@@ -369,7 +378,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:322:11
+  --> $DIR/empty-types.rs:313:11
    |
 LL |     match *x {}
    |           ^^
@@ -383,7 +392,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:327:11
+  --> $DIR/empty-types.rs:318:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -397,12 +406,13 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[!, ..]` not covered
-  --> $DIR/empty-types.rs:329:11
+  --> $DIR/empty-types.rs:320:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[!, ..]` not covered
    |
    = note: the matched value is of type `&[!]`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         [] => {},
@@ -410,7 +420,7 @@ LL +         &[!, ..]
    |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[!]` and `&[!, !]` not covered
-  --> $DIR/empty-types.rs:338:11
+  --> $DIR/empty-types.rs:329:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]`, `&[!]` and `&[!, !]` not covered
@@ -423,7 +433,7 @@ LL +         &[] | &[!] | &[!, !] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[!, ..]` not covered
-  --> $DIR/empty-types.rs:352:11
+  --> $DIR/empty-types.rs:343:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]` and `&[!, ..]` not covered
@@ -437,7 +447,7 @@ LL +         &[] | &[!, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:359:11
+  --> $DIR/empty-types.rs:350:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -450,22 +460,32 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:366:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:359:9
    |
-LL |     match array_3_never {}
-   |           ^^^^^^^^^^^^^
+LL |         _ => {}
+   |         ^
    |
-   = note: the matched value is of type `[!; 3]`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:362:9
    |
-LL ~     match array_3_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         [_, _, _] => {}
+   |         ^^^^^^^^^
    |
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:365:9
+   |
+LL |         [_, ..] => {}
+   |         ^^^^^^^
+   |
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:389:11
+  --> $DIR/empty-types.rs:379:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -479,7 +499,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:396:9
+  --> $DIR/empty-types.rs:386:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -487,7 +507,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:398:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -500,8 +520,42 @@ LL ~         [..] if false => {},
 LL +         [] => todo!()
    |
 
+error: unreachable pattern
+  --> $DIR/empty-types.rs:407:9
+   |
+LL |         Some(_) => {}
+   |         ^^^^^^^
+   |
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:412:9
+   |
+LL |         Some(_a) => {}
+   |         ^^^^^^^^
+   |
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:417:9
+   |
+LL |         None => {}
+   |         ---- matches all the values already
+LL |         // !useful, !reachable
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:422:9
+   |
+LL |         None => {}
+   |         ---- matches all the values already
+LL |         // !useful, !reachable
+LL |         _a => {}
+   |         ^^ unreachable pattern
+
 error[E0004]: non-exhaustive patterns: `&Some(!)` not covered
-  --> $DIR/empty-types.rs:452:11
+  --> $DIR/empty-types.rs:442:11
    |
 LL |     match ref_opt_never {
    |           ^^^^^^^^^^^^^ pattern `&Some(!)` not covered
@@ -512,6 +566,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `&Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &None => {},
@@ -519,7 +574,7 @@ LL +         &Some(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:493:11
+  --> $DIR/empty-types.rs:483:11
    |
 LL |     match *ref_opt_never {
    |           ^^^^^^^^^^^^^^ pattern `Some(!)` not covered
@@ -530,6 +585,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
@@ -537,7 +593,7 @@ LL +         Some(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:541:11
+  --> $DIR/empty-types.rs:531:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(!)` not covered
@@ -548,6 +604,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_) => {},
@@ -555,7 +612,7 @@ LL +         Err(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:552:11
+  --> $DIR/empty-types.rs:542:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(!)` not covered
@@ -566,6 +623,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_a) => {},
@@ -573,7 +631,7 @@ LL +         Err(!)
    |
 
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:571:11
+  --> $DIR/empty-types.rs:561:11
    |
 LL |     match *ref_tuple_half_never {}
    |           ^^^^^^^^^^^^^^^^^^^^^
@@ -587,7 +645,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:604:9
+  --> $DIR/empty-types.rs:594:9
    |
 LL |         _ => {}
    |         ^
@@ -595,7 +653,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:607:9
+  --> $DIR/empty-types.rs:597:9
    |
 LL |         _x => {}
    |         ^^
@@ -603,7 +661,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:610:9
+  --> $DIR/empty-types.rs:600:9
    |
 LL |         _ if false => {}
    |         ^
@@ -611,7 +669,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:613:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _x if false => {}
    |         ^^
@@ -619,12 +677,13 @@ LL |         _x if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `&!` not covered
-  --> $DIR/empty-types.rs:638:11
+  --> $DIR/empty-types.rs:628:11
    |
 LL |     match ref_never {
    |           ^^^^^^^^^ pattern `&!` not covered
    |
    = note: the matched value is of type `&!`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: references are always considered inhabited
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
@@ -634,7 +693,7 @@ LL +         &!
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(!)` not covered
-  --> $DIR/empty-types.rs:654:11
+  --> $DIR/empty-types.rs:644:11
    |
 LL |     match *ref_result_never {
    |           ^^^^^^^^^^^^^^^^^ pattern `Ok(!)` not covered
@@ -645,6 +704,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Err(_) => {},
@@ -652,7 +712,7 @@ LL +         Ok(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:674:11
+  --> $DIR/empty-types.rs:664:11
    |
 LL |     match *x {
    |           ^^ pattern `Some(!)` not covered
@@ -663,13 +723,14 @@ note: `Option<Result<!, !>>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Result<!, !>>`
+   = note: `Result<!, !>` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
 LL +         Some(!)
    |
 
-error: aborting due to 49 previous errors; 1 warning emitted
+error: aborting due to 64 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0004, E0005.
 For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr
index 78db9ee349b..c3421cd592e 100644
--- a/tests/ui/pattern/usefulness/empty-types.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/empty-types.rs:51:9
+  --> $DIR/empty-types.rs:49:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 note: the lint level is defined here
-  --> $DIR/empty-types.rs:17:9
+  --> $DIR/empty-types.rs:15:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:54:9
+  --> $DIR/empty-types.rs:52:9
    |
 LL |         _x => {}
    |         ^^
@@ -20,7 +20,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/empty-types.rs:58:11
+  --> $DIR/empty-types.rs:56:11
    |
 LL |     match ref_never {}
    |           ^^^^^^^^^
@@ -34,84 +34,75 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:70:11
-   |
-LL |     match tuple_half_never {}
-   |           ^^^^^^^^^^^^^^^^
-   |
-   = note: the matched value is of type `(u32, !)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+error: unreachable pattern
+  --> $DIR/empty-types.rs:70:9
    |
-LL ~     match tuple_half_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         (_, _) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `(u32, !)` is uninhabited
 
-error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:77:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:76:9
    |
-LL |     match tuple_never {}
-   |           ^^^^^^^^^^^
+LL |         _ => {}
+   |         ^
    |
-   = note: the matched value is of type `(!, !)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   = note: this pattern matches no values because `(!, !)` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:79:9
    |
-LL ~     match tuple_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         (_, _) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:87:9
+  --> $DIR/empty-types.rs:83:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered
-  --> $DIR/empty-types.rs:91:11
+error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
+  --> $DIR/empty-types.rs:87:11
    |
 LL |     match res_u32_never {}
-   |           ^^^^^^^^^^^^^ patterns `Ok(_)` and `Err(_)` not covered
+   |           ^^^^^^^^^^^^^ pattern `Ok(_)` not covered
    |
 note: `Result<u32, !>` defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
    = note: not covered
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Result<u32, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~     match res_u32_never {
-LL +         Ok(_) | Err(_) => todo!(),
+LL +         Ok(_) => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:93:11
-   |
-LL |     match res_u32_never {
-   |           ^^^^^^^^^^^^^ pattern `Err(_)` not covered
+error: unreachable pattern
+  --> $DIR/empty-types.rs:94:9
    |
-note: `Result<u32, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+LL |         Err(_) => {}
+   |         ^^^^^^
    |
-   = note: not covered
-   = note: the matched value is of type `Result<u32, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:99:9
    |
-LL ~         Ok(_) => {},
-LL +         Err(_) => todo!()
+LL |         Err(_) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered
-  --> $DIR/empty-types.rs:101:11
+  --> $DIR/empty-types.rs:96:11
    |
 LL |     match res_u32_never {
    |           ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered
@@ -129,21 +120,7 @@ LL ~         Ok(1_u32..=u32::MAX) => todo!()
    |
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:106:9
-   |
-LL |     let Ok(_x) = res_u32_never;
-   |         ^^^^^^ pattern `Err(_)` not covered
-   |
-   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `Result<u32, !>`
-help: you might want to use `let else` to handle the variant that isn't matched
-   |
-LL |     let Ok(_x) = res_u32_never else { todo!() };
-   |                                ++++++++++++++++
-
-error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:108:9
+  --> $DIR/empty-types.rs:102:9
    |
 LL |     let Ok(_x) = res_u32_never.as_ref();
    |         ^^^^^^ pattern `Err(_)` not covered
@@ -157,7 +134,7 @@ LL |     let Ok(_x) = res_u32_never.as_ref() else { todo!() };
    |                                         ++++++++++++++++
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:112:9
+  --> $DIR/empty-types.rs:106:9
    |
 LL |     let Ok(_x) = &res_u32_never;
    |         ^^^^^^ pattern `&Err(_)` not covered
@@ -170,47 +147,56 @@ help: you might want to use `let else` to handle the variant that isn't matched
 LL |     let Ok(_x) = &res_u32_never else { todo!() };
    |                                 ++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered
-  --> $DIR/empty-types.rs:116:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:112:9
    |
-LL |     match result_never {}
-   |           ^^^^^^^^^^^^ patterns `Ok(_)` and `Err(_)` not covered
+LL |         _ => {}
+   |         ^
    |
-note: `Result<!, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:115:9
    |
-   = note: not covered
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
-   = note: not covered
-   = note: the matched value is of type `Result<!, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:118:9
    |
-LL ~     match result_never {
-LL +         Ok(_) | Err(_) => todo!(),
-LL +     }
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:121:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:119:9
    |
-LL |     match result_never {
-   |           ^^^^^^^^^^^^ pattern `Err(_)` not covered
+LL |         _ => {}
+   |         ^
    |
-note: `Result<!, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:122:9
    |
-   = note: not covered
-   = note: the matched value is of type `Result<!, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+LL |         Ok(_) => {}
+   |         ^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:123:9
    |
-LL |         Ok(_) => {}, Err(_) => todo!()
-   |                    +++++++++++++++++++
+LL |         Err(_) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:140:13
+  --> $DIR/empty-types.rs:132:13
    |
 LL |             _ => {}
    |             ^
@@ -218,33 +204,31 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:143:13
+  --> $DIR/empty-types.rs:135:13
    |
 LL |             _ if false => {}
    |             ^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:146:15
-   |
-LL |         match opt_void {
-   |               ^^^^^^^^ pattern `Some(_)` not covered
-   |
-note: `Option<Void>` defined here
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+error: unreachable pattern
+  --> $DIR/empty-types.rs:143:13
    |
-   = note: not covered
-   = note: the matched value is of type `Option<Void>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+LL |             Some(_) => {}
+   |             ^^^^^^^
    |
-LL ~             None => {},
-LL +             Some(_) => todo!()
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:147:13
    |
+LL |             None => {}
+   |             ---- matches all the values already
+LL |             _ => {}
+   |             ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:165:15
+  --> $DIR/empty-types.rs:156:15
    |
 LL |         match *ref_opt_void {
    |               ^^^^^^^^^^^^^ pattern `Some(_)` not covered
@@ -255,6 +239,7 @@ note: `Option<Void>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~             None => {},
@@ -262,7 +247,7 @@ LL +             Some(_) => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:208:13
+  --> $DIR/empty-types.rs:199:13
    |
 LL |             _ => {}
    |             ^
@@ -270,7 +255,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:213:13
+  --> $DIR/empty-types.rs:204:13
    |
 LL |             _ => {}
    |             ^
@@ -278,7 +263,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:218:13
+  --> $DIR/empty-types.rs:209:13
    |
 LL |             _ => {}
    |             ^
@@ -286,7 +271,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:223:13
+  --> $DIR/empty-types.rs:214:13
    |
 LL |             _ => {}
    |             ^
@@ -294,7 +279,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:229:13
+  --> $DIR/empty-types.rs:220:13
    |
 LL |             _ => {}
    |             ^
@@ -302,15 +287,39 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:288:9
+  --> $DIR/empty-types.rs:279:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 
+error: unreachable pattern
+  --> $DIR/empty-types.rs:282:9
+   |
+LL |         (_, _) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `(!, !)` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:285:9
+   |
+LL |         Ok(_) => {}
+   |         ^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:286:9
+   |
+LL |         Err(_) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:316:11
+  --> $DIR/empty-types.rs:307:11
    |
 LL |     match *x {}
    |           ^^
@@ -324,7 +333,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:318:11
+  --> $DIR/empty-types.rs:309:11
    |
 LL |     match *x {}
    |           ^^
@@ -338,7 +347,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered
-  --> $DIR/empty-types.rs:320:11
+  --> $DIR/empty-types.rs:311:11
    |
 LL |     match *x {}
    |           ^^ patterns `Ok(_)` and `Err(_)` not covered
@@ -360,7 +369,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:322:11
+  --> $DIR/empty-types.rs:313:11
    |
 LL |     match *x {}
    |           ^^
@@ -374,7 +383,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:327:11
+  --> $DIR/empty-types.rs:318:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -388,12 +397,13 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
-  --> $DIR/empty-types.rs:329:11
+  --> $DIR/empty-types.rs:320:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[_, ..]` not covered
    |
    = note: the matched value is of type `&[!]`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         [] => {},
@@ -401,7 +411,7 @@ LL +         &[_, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[_]` and `&[_, _]` not covered
-  --> $DIR/empty-types.rs:338:11
+  --> $DIR/empty-types.rs:329:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _]` not covered
@@ -414,7 +424,7 @@ LL +         &[] | &[_] | &[_, _] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered
-  --> $DIR/empty-types.rs:352:11
+  --> $DIR/empty-types.rs:343:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]` and `&[_, ..]` not covered
@@ -428,7 +438,7 @@ LL +         &[] | &[_, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:359:11
+  --> $DIR/empty-types.rs:350:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -441,22 +451,32 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:366:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:359:9
    |
-LL |     match array_3_never {}
-   |           ^^^^^^^^^^^^^
+LL |         _ => {}
+   |         ^
    |
-   = note: the matched value is of type `[!; 3]`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:362:9
    |
-LL ~     match array_3_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         [_, _, _] => {}
+   |         ^^^^^^^^^
+   |
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:365:9
+   |
+LL |         [_, ..] => {}
+   |         ^^^^^^^
    |
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:389:11
+  --> $DIR/empty-types.rs:379:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -470,7 +490,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:396:9
+  --> $DIR/empty-types.rs:386:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -478,7 +498,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:398:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -491,8 +511,42 @@ LL ~         [..] if false => {},
 LL +         [] => todo!()
    |
 
+error: unreachable pattern
+  --> $DIR/empty-types.rs:407:9
+   |
+LL |         Some(_) => {}
+   |         ^^^^^^^
+   |
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:412:9
+   |
+LL |         Some(_a) => {}
+   |         ^^^^^^^^
+   |
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:417:9
+   |
+LL |         None => {}
+   |         ---- matches all the values already
+LL |         // !useful, !reachable
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:422:9
+   |
+LL |         None => {}
+   |         ---- matches all the values already
+LL |         // !useful, !reachable
+LL |         _a => {}
+   |         ^^ unreachable pattern
+
 error[E0004]: non-exhaustive patterns: `&Some(_)` not covered
-  --> $DIR/empty-types.rs:452:11
+  --> $DIR/empty-types.rs:442:11
    |
 LL |     match ref_opt_never {
    |           ^^^^^^^^^^^^^ pattern `&Some(_)` not covered
@@ -503,6 +557,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `&Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &None => {},
@@ -510,7 +565,7 @@ LL +         &Some(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:493:11
+  --> $DIR/empty-types.rs:483:11
    |
 LL |     match *ref_opt_never {
    |           ^^^^^^^^^^^^^^ pattern `Some(_)` not covered
@@ -521,6 +576,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
@@ -528,7 +584,7 @@ LL +         Some(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:541:11
+  --> $DIR/empty-types.rs:531:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(_)` not covered
@@ -539,6 +595,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_) => {},
@@ -546,7 +603,7 @@ LL +         Err(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:552:11
+  --> $DIR/empty-types.rs:542:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(_)` not covered
@@ -557,6 +614,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_a) => {},
@@ -564,7 +622,7 @@ LL +         Err(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:571:11
+  --> $DIR/empty-types.rs:561:11
    |
 LL |     match *ref_tuple_half_never {}
    |           ^^^^^^^^^^^^^^^^^^^^^
@@ -578,7 +636,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:604:9
+  --> $DIR/empty-types.rs:594:9
    |
 LL |         _ => {}
    |         ^
@@ -586,7 +644,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:607:9
+  --> $DIR/empty-types.rs:597:9
    |
 LL |         _x => {}
    |         ^^
@@ -594,7 +652,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:610:9
+  --> $DIR/empty-types.rs:600:9
    |
 LL |         _ if false => {}
    |         ^
@@ -602,7 +660,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:613:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _x if false => {}
    |         ^^
@@ -610,12 +668,13 @@ LL |         _x if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `&_` not covered
-  --> $DIR/empty-types.rs:638:11
+  --> $DIR/empty-types.rs:628:11
    |
 LL |     match ref_never {
    |           ^^^^^^^^^ pattern `&_` not covered
    |
    = note: the matched value is of type `&!`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: references are always considered inhabited
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
@@ -625,7 +684,7 @@ LL +         &_ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
-  --> $DIR/empty-types.rs:654:11
+  --> $DIR/empty-types.rs:644:11
    |
 LL |     match *ref_result_never {
    |           ^^^^^^^^^^^^^^^^^ pattern `Ok(_)` not covered
@@ -636,6 +695,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Err(_) => {},
@@ -643,7 +703,7 @@ LL +         Ok(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:674:11
+  --> $DIR/empty-types.rs:664:11
    |
 LL |     match *x {
    |           ^^ pattern `Some(_)` not covered
@@ -654,13 +714,14 @@ note: `Option<Result<!, !>>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Result<!, !>>`
+   = note: `Result<!, !>` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
 LL +         Some(_) => todo!()
    |
 
-error: aborting due to 49 previous errors
+error: aborting due to 64 previous errors
 
 Some errors have detailed explanations: E0004, E0005.
 For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-types.rs b/tests/ui/pattern/usefulness/empty-types.rs
index cc71f67831d..639c48cea12 100644
--- a/tests/ui/pattern/usefulness/empty-types.rs
+++ b/tests/ui/pattern/usefulness/empty-types.rs
@@ -1,5 +1,4 @@
-//@ revisions: normal min_exh_pats exhaustive_patterns never_pats
-// gate-test-min_exhaustive_patterns
+//@ revisions: normal exhaustive_patterns never_pats
 //
 // This tests correct handling of empty types in exhaustiveness checking.
 //
@@ -10,7 +9,6 @@
 // This feature is useful to avoid `!` falling back to `()` all the time.
 #![feature(never_type_fallback)]
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exh_pats, feature(min_exhaustive_patterns))]
 #![cfg_attr(never_pats, feature(never_patterns))]
 //[never_pats]~^ WARN the feature `never_patterns` is incomplete
 #![allow(dead_code, unreachable_code)]
@@ -68,19 +66,17 @@ fn basic(x: NeverBundle) {
 
     let tuple_half_never: (u32, !) = x.tuple_half_never;
     match tuple_half_never {}
-    //[normal,never_pats]~^ ERROR non-empty
     match tuple_half_never {
-        (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 
     let tuple_never: (!, !) = x.tuple_never;
     match tuple_never {}
-    //[normal,never_pats]~^ ERROR non-empty
     match tuple_never {
-        _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match tuple_never {
-        (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match tuple_never.0 {}
     match tuple_never.0 {
@@ -91,44 +87,40 @@ fn basic(x: NeverBundle) {
     match res_u32_never {}
     //~^ ERROR non-exhaustive
     match res_u32_never {
-        //[normal,never_pats]~^ ERROR non-exhaustive
         Ok(_) => {}
     }
     match res_u32_never {
         Ok(_) => {}
-        Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match res_u32_never {
         //~^ ERROR non-exhaustive
         Ok(0) => {}
-        Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     let Ok(_x) = res_u32_never;
-    //[normal,never_pats]~^ ERROR refutable
     let Ok(_x) = res_u32_never.as_ref();
     //~^ ERROR refutable
     // Non-obvious difference: here there's an implicit dereference in the patterns, which makes the
     // inner place !known_valid. `exhaustive_patterns` ignores this.
     let Ok(_x) = &res_u32_never;
-    //[normal,min_exh_pats,never_pats]~^ ERROR refutable
+    //[normal,never_pats]~^ ERROR refutable
 
     let result_never: Result<!, !> = x.result_never;
     match result_never {}
-    //[normal,never_pats]~^ ERROR non-exhaustive
     match result_never {
-        _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match result_never {
-        //[normal,never_pats]~^ ERROR non-exhaustive
-        Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Ok(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match result_never {
-        Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
-        _ => {}     //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Ok(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
+        _ => {}     //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match result_never {
-        Ok(_) => {}  //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
-        Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Ok(_) => {}  //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
+        Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 }
 
@@ -144,16 +136,15 @@ fn void_same_as_never(x: NeverBundle) {
         }
         let opt_void: Option<Void> = None;
         match opt_void {
-            //[normal,never_pats]~^ ERROR non-exhaustive
             None => {}
         }
         match opt_void {
             None => {}
-            Some(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+            Some(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
         }
         match opt_void {
             None => {}
-            _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+            _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
         }
 
         let ref_void: &Void = &x.void;
@@ -163,7 +154,7 @@ fn void_same_as_never(x: NeverBundle) {
         }
         let ref_opt_void: &Option<Void> = &None;
         match *ref_opt_void {
-            //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+            //[normal,never_pats]~^ ERROR non-exhaustive
             None => {}
         }
         match *ref_opt_void {
@@ -288,11 +279,11 @@ fn nested_validity_tracking(bundle: NeverBundle) {
         _ => {} //~ ERROR unreachable pattern
     }
     match tuple_never {
-        (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match result_never {
-        Ok(_) => {}  //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
-        Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Ok(_) => {}  //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
+        Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 
     // These should be considered !known_valid and not warn unreachable.
@@ -313,13 +304,13 @@ fn invalid_empty_match(bundle: NeverBundle) {
     match *x {}
 
     let x: &(u32, !) = &bundle.tuple_half_never;
-    match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
+    match *x {} //[normal,never_pats]~ ERROR non-exhaustive
     let x: &(!, !) = &bundle.tuple_never;
-    match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
+    match *x {} //[normal,never_pats]~ ERROR non-exhaustive
     let x: &Result<!, !> = &bundle.result_never;
-    match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
+    match *x {} //[normal,never_pats]~ ERROR non-exhaustive
     let x: &[!; 3] = &bundle.array_3_never;
-    match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
+    match *x {} //[normal,never_pats]~ ERROR non-exhaustive
 }
 
 fn arrays_and_slices(x: NeverBundle) {
@@ -327,7 +318,7 @@ fn arrays_and_slices(x: NeverBundle) {
     match slice_never {}
     //~^ ERROR non-empty
     match slice_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR not covered
+        //[normal,never_pats]~^ ERROR not covered
         [] => {}
     }
     match slice_never {
@@ -336,7 +327,7 @@ fn arrays_and_slices(x: NeverBundle) {
         [_, _, ..] => {}
     }
     match slice_never {
-        //[normal,min_exh_pats]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered
+        //[normal]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered
         //[exhaustive_patterns]~^^ ERROR `&[]` not covered
         //[never_pats]~^^^ ERROR `&[]`, `&[!]` and `&[!, !]` not covered
         [_, _, _, ..] => {}
@@ -350,7 +341,7 @@ fn arrays_and_slices(x: NeverBundle) {
         _x => {}
     }
     match slice_never {
-        //[normal,min_exh_pats]~^ ERROR `&[]` and `&[_, ..]` not covered
+        //[normal]~^ ERROR `&[]` and `&[_, ..]` not covered
         //[exhaustive_patterns]~^^ ERROR `&[]` not covered
         //[never_pats]~^^^ ERROR `&[]` and `&[!, ..]` not covered
         &[..] if false => {}
@@ -364,15 +355,14 @@ fn arrays_and_slices(x: NeverBundle) {
 
     let array_3_never: [!; 3] = x.array_3_never;
     match array_3_never {}
-    //[normal,never_pats]~^ ERROR non-empty
     match array_3_never {
-        _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match array_3_never {
-        [_, _, _] => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        [_, _, _] => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match array_3_never {
-        [_, ..] => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        [_, ..] => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 
     let ref_array_3_never: &[!; 3] = &array_3_never;
@@ -414,22 +404,22 @@ fn bindings(x: NeverBundle) {
     match opt_never {
         None => {}
         // !useful, !reachable
-        Some(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Some(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match opt_never {
         None => {}
         // !useful, !reachable
-        Some(_a) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Some(_a) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match opt_never {
         None => {}
         // !useful, !reachable
-        _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match opt_never {
         None => {}
         // !useful, !reachable
-        _a => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _a => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 
     // The scrutinee is known_valid, but under the `&` isn't anymore.
@@ -450,7 +440,7 @@ fn bindings(x: NeverBundle) {
         &_a => {}
     }
     match ref_opt_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         &None => {}
     }
     match ref_opt_never {
@@ -491,7 +481,7 @@ fn bindings(x: NeverBundle) {
         ref _a => {}
     }
     match *ref_opt_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         None => {}
     }
     match *ref_opt_never {
@@ -539,7 +529,7 @@ fn bindings(x: NeverBundle) {
 
     let ref_res_never: &Result<!, !> = &x.result_never;
     match *ref_res_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         // useful, reachable
         Ok(_) => {}
     }
@@ -550,7 +540,7 @@ fn bindings(x: NeverBundle) {
         _ => {}
     }
     match *ref_res_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         // useful, !reachable
         Ok(_a) => {}
     }
@@ -569,7 +559,7 @@ fn bindings(x: NeverBundle) {
 
     let ref_tuple_half_never: &(u32, !) = &x.tuple_half_never;
     match *ref_tuple_half_never {}
-    //[normal,min_exh_pats,never_pats]~^ ERROR non-empty
+    //[normal,never_pats]~^ ERROR non-empty
     match *ref_tuple_half_never {
         // useful, reachable
         (_, _) => {}
@@ -636,7 +626,7 @@ fn guards_and_validity(x: NeverBundle) {
         _a if false => {}
     }
     match ref_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         // useful, !reachable
         &_a if false => {}
     }
@@ -652,7 +642,7 @@ fn guards_and_validity(x: NeverBundle) {
         Err(_) => {}
     }
     match *ref_result_never {
-        //[normal,min_exh_pats]~^ ERROR `Ok(_)` not covered
+        //[normal]~^ ERROR `Ok(_)` not covered
         //[never_pats]~^^ ERROR `Ok(!)` not covered
         // useful, reachable
         Ok(_) if false => {}
@@ -672,7 +662,7 @@ fn diagnostics_subtlety(x: NeverBundle) {
     // Regression test for diagnostics: don't report `Some(Ok(_))` and `Some(Err(_))`.
     let x: &Option<Result<!, !>> = &None;
     match *x {
-        //[normal,min_exh_pats]~^ ERROR `Some(_)` not covered
+        //[normal]~^ ERROR `Some(_)` not covered
         //[never_pats]~^^ ERROR `Some(!)` not covered
         None => {}
     }
diff --git a/tests/ui/pattern/usefulness/explain-unreachable-pats.rs b/tests/ui/pattern/usefulness/explain-unreachable-pats.rs
index 98f781b6a09..44d194055d9 100644
--- a/tests/ui/pattern/usefulness/explain-unreachable-pats.rs
+++ b/tests/ui/pattern/usefulness/explain-unreachable-pats.rs
@@ -1,5 +1,4 @@
 #![feature(never_type)]
-#![feature(min_exhaustive_patterns)]
 #![deny(unreachable_patterns)]
 //~^ NOTE lint level is defined here
 
diff --git a/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr b/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr
index e2eecf4a9f3..105d4f73f66 100644
--- a/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr
+++ b/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:11:9
+  --> $DIR/explain-unreachable-pats.rs:10:9
    |
 LL |         (1 | 2,) => {}
    |         -------- matches all the values already
@@ -8,19 +8,19 @@ LL |         (2,) => {}
    |         ^^^^ unreachable pattern
    |
 note: the lint level is defined here
-  --> $DIR/explain-unreachable-pats.rs:3:9
+  --> $DIR/explain-unreachable-pats.rs:2:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:22:9
+  --> $DIR/explain-unreachable-pats.rs:21:9
    |
 LL |         (1 | 2,) => {}
    |         ^^^^^^^^ unreachable pattern
    |
 note: these patterns collectively make the last one unreachable
-  --> $DIR/explain-unreachable-pats.rs:22:9
+  --> $DIR/explain-unreachable-pats.rs:21:9
    |
 LL |         (1,) => {}
    |         ---- matches some of the same values
@@ -32,7 +32,7 @@ LL |         (1 | 2,) => {}
    |         ^^^^^^^^ collectively making this unreachable
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:33:9
+  --> $DIR/explain-unreachable-pats.rs:32:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -40,7 +40,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:46:9
+  --> $DIR/explain-unreachable-pats.rs:45:9
    |
 LL |         (Err(_), Err(_)) => {}
    |         ^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |         (Err(_), Err(_)) => {}
    = note: this pattern matches no values because `Void2` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:52:9
+  --> $DIR/explain-unreachable-pats.rs:51:9
    |
 LL |         (Err(_), Err(_)) => {}
    |         ^^^^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |         (Err(_), Err(_)) => {}
    = note: this pattern matches no values because `Void1` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:61:11
+  --> $DIR/explain-unreachable-pats.rs:60:11
    |
 LL |     if let (0
    |             - matches all the values already
@@ -65,13 +65,13 @@ LL |         | 0, _) = (0, 0) {}
    |           ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:71:9
+  --> $DIR/explain-unreachable-pats.rs:70:9
    |
 LL |         (_, true) => {}
    |         ^^^^^^^^^ unreachable pattern
    |
 note: these patterns collectively make the last one unreachable
-  --> $DIR/explain-unreachable-pats.rs:71:9
+  --> $DIR/explain-unreachable-pats.rs:70:9
    |
 LL |         (true, _) => {}
    |         --------- matches some of the same values
@@ -83,7 +83,7 @@ LL |         (_, true) => {}
    |         ^^^^^^^^^ collectively making this unreachable
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:84:9
+  --> $DIR/explain-unreachable-pats.rs:83:9
    |
 LL |         (true, _) => {}
    |         --------- matches all the values already
@@ -92,7 +92,7 @@ LL |         (true, true) => {}
    |         ^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:96:9
+  --> $DIR/explain-unreachable-pats.rs:95:9
    |
 LL |         (_, true, 0..10) => {}
    |         ---------------- matches all the values already
diff --git a/tests/ui/pattern/usefulness/impl-trait.rs b/tests/ui/pattern/usefulness/impl-trait.rs
index 1fec9a2633e..c1cc279f74c 100644
--- a/tests/ui/pattern/usefulness/impl-trait.rs
+++ b/tests/ui/pattern/usefulness/impl-trait.rs
@@ -1,5 +1,4 @@
 #![feature(never_type)]
-#![feature(min_exhaustive_patterns)]
 #![feature(type_alias_impl_trait)]
 #![feature(non_exhaustive_omitted_patterns_lint)]
 #![deny(unreachable_patterns)]
diff --git a/tests/ui/pattern/usefulness/impl-trait.stderr b/tests/ui/pattern/usefulness/impl-trait.stderr
index c079f5a259d..92932e48538 100644
--- a/tests/ui/pattern/usefulness/impl-trait.stderr
+++ b/tests/ui/pattern/usefulness/impl-trait.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:17:13
+  --> $DIR/impl-trait.rs:16:13
    |
 LL |             _ => {}
    |             ^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 note: the lint level is defined here
-  --> $DIR/impl-trait.rs:5:9
+  --> $DIR/impl-trait.rs:4:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:31:13
+  --> $DIR/impl-trait.rs:30:13
    |
 LL |             _ => {}
    |             ^
@@ -20,7 +20,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:45:13
+  --> $DIR/impl-trait.rs:44:13
    |
 LL |             Some(_) => {}
    |             ^^^^^^^
@@ -28,7 +28,7 @@ LL |             Some(_) => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:49:13
+  --> $DIR/impl-trait.rs:48:13
    |
 LL |             None => {}
    |             ---- matches all the values already
@@ -36,7 +36,7 @@ LL |             _ => {}
    |             ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:59:13
+  --> $DIR/impl-trait.rs:58:13
    |
 LL |             Some(_) => {}
    |             ^^^^^^^
@@ -44,7 +44,7 @@ LL |             Some(_) => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:63:13
+  --> $DIR/impl-trait.rs:62:13
    |
 LL |             None => {}
    |             ---- matches all the values already
@@ -52,7 +52,7 @@ LL |             _ => {}
    |             ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:76:9
+  --> $DIR/impl-trait.rs:75:9
    |
 LL |         _ => {}
    |         ^
@@ -60,7 +60,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:86:9
+  --> $DIR/impl-trait.rs:85:9
    |
 LL |         _ => {}
    |         - matches any value
@@ -68,7 +68,7 @@ LL |         Some((a, b)) => {}
    |         ^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:94:13
+  --> $DIR/impl-trait.rs:93:13
    |
 LL |             _ => {}
    |             ^
@@ -76,7 +76,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:105:9
+  --> $DIR/impl-trait.rs:104:9
    |
 LL |         Some((a, b)) => {}
    |         ------------ matches all the values already
@@ -84,7 +84,7 @@ LL |         Some((mut x, mut y)) => {
    |         ^^^^^^^^^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:124:13
+  --> $DIR/impl-trait.rs:123:13
    |
 LL |             _ => {}
    |             - matches any value
@@ -92,7 +92,7 @@ LL |             Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:138:13
+  --> $DIR/impl-trait.rs:137:13
    |
 LL |             _ => {}
    |             ^
@@ -100,7 +100,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `SecretelyVoid` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:151:13
+  --> $DIR/impl-trait.rs:150:13
    |
 LL |             _ => {}
    |             ^
@@ -108,7 +108,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `SecretelyDoubleVoid` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty
-  --> $DIR/impl-trait.rs:23:11
+  --> $DIR/impl-trait.rs:22:11
    |
 LL |     match return_never_rpit(x) {}
    |           ^^^^^^^^^^^^^^^^^^^^
@@ -122,7 +122,7 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: type `T` is non-empty
-  --> $DIR/impl-trait.rs:37:11
+  --> $DIR/impl-trait.rs:36:11
    |
 LL |     match return_never_tait(x) {}
    |           ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr
index 261a4b3353f..463e104f970 100644
--- a/tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
-  --> $DIR/match-privately-empty.rs:15:11
+  --> $DIR/match-privately-empty.rs:14:11
    |
 LL |     match private::DATA {
    |           ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.normal.stderr b/tests/ui/pattern/usefulness/match-privately-empty.normal.stderr
new file mode 100644
index 00000000000..463e104f970
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-privately-empty.normal.stderr
@@ -0,0 +1,21 @@
+error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
+  --> $DIR/match-privately-empty.rs:14:11
+   |
+LL |     match private::DATA {
+   |           ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
+   |
+note: `Option<Private>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+  ::: $SRC_DIR/core/src/option.rs:LL:COL
+   |
+   = note: not covered
+   = note: the matched value is of type `Option<Private>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Some(private::Private { misc: false, .. }) => {},
+LL +         Some(Private { misc: true, .. }) => todo!()
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.rs b/tests/ui/pattern/usefulness/match-privately-empty.rs
index 7e1d0dc48f2..bfea15af180 100644
--- a/tests/ui/pattern/usefulness/match-privately-empty.rs
+++ b/tests/ui/pattern/usefulness/match-privately-empty.rs
@@ -1,6 +1,5 @@
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 
 mod private {
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr
index e5e581447e6..c4fcd67cfdb 100644
--- a/tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `&[]` not covered
-  --> $DIR/slice_of_empty.rs:21:11
+  --> $DIR/slice_of_empty.rs:20:11
    |
 LL |     match nevers {
    |           ^^^^^^ pattern `&[]` not covered
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.normal.stderr b/tests/ui/pattern/usefulness/slice_of_empty.normal.stderr
new file mode 100644
index 00000000000..c9afd1bfc90
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice_of_empty.normal.stderr
@@ -0,0 +1,30 @@
+error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
+  --> $DIR/slice_of_empty.rs:9:11
+   |
+LL |     match nevers {
+   |           ^^^^^^ pattern `&[_, ..]` not covered
+   |
+   = note: the matched value is of type `&[!]`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         &[] => (),
+LL ~         &[_, ..] => todo!(),
+   |
+
+error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
+  --> $DIR/slice_of_empty.rs:20:11
+   |
+LL |     match nevers {
+   |           ^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered
+   |
+   = note: the matched value is of type `&[!]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         &[_] => (),
+LL ~         &[] | &[_, _, ..] => todo!(),
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.rs b/tests/ui/pattern/usefulness/slice_of_empty.rs
index 785fccaabf7..e186ba5134d 100644
--- a/tests/ui/pattern/usefulness/slice_of_empty.rs
+++ b/tests/ui/pattern/usefulness/slice_of_empty.rs
@@ -1,6 +1,5 @@
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 #![deny(unreachable_patterns)]
 
@@ -8,7 +7,7 @@ fn main() {}
 
 fn foo(nevers: &[!]) {
     match nevers {
-        //[min_exhaustive_patterns]~^ ERROR non-exhaustive patterns: `&[_, ..]` not covered
+        //[normal]~^ ERROR non-exhaustive patterns: `&[_, ..]` not covered
         &[] => (),
     };
 
@@ -20,7 +19,7 @@ fn foo(nevers: &[!]) {
 
     match nevers {
         //[exhaustive_patterns]~^ ERROR non-exhaustive patterns: `&[]` not covered
-        //[min_exhaustive_patterns]~^^ ERROR non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
+        //[normal]~^^ ERROR non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
         &[_] => (),
     };
 }
diff --git a/tests/ui/pattern/usefulness/uninhabited.rs b/tests/ui/pattern/usefulness/uninhabited.rs
index 72e602ee8d2..5c774b7874a 100644
--- a/tests/ui/pattern/usefulness/uninhabited.rs
+++ b/tests/ui/pattern/usefulness/uninhabited.rs
@@ -5,7 +5,6 @@
 // `Ty::is_inhabited_from` function.
 #![feature(never_type)]
 #![feature(never_type_fallback)]
-#![feature(min_exhaustive_patterns)]
 #![deny(unreachable_patterns)]
 
 macro_rules! assert_empty {
diff --git a/tests/ui/polymorphization/inline-tainted-body.rs b/tests/ui/polymorphization/inline-tainted-body.rs
new file mode 100644
index 00000000000..13aec97e22b
--- /dev/null
+++ b/tests/ui/polymorphization/inline-tainted-body.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes
+
+#![feature(unboxed_closures)]
+
+use std::sync::Arc;
+
+pub struct WeakOnce<T>();
+//~^ ERROR type parameter `T` is never used
+
+impl<T> WeakOnce<T> {
+    extern "rust-call" fn try_get(&self) -> Option<Arc<T>> {}
+    //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
+    //~| ERROR mismatched types
+
+    pub fn get(&self) -> Arc<T> {
+        self.try_get()
+            .unwrap_or_else(|| panic!("Singleton {} not available", std::any::type_name::<T>()))
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/polymorphization/inline-tainted-body.stderr b/tests/ui/polymorphization/inline-tainted-body.stderr
new file mode 100644
index 00000000000..5c3bd70adae
--- /dev/null
+++ b/tests/ui/polymorphization/inline-tainted-body.stderr
@@ -0,0 +1,30 @@
+error[E0392]: type parameter `T` is never used
+  --> $DIR/inline-tainted-body.rs:7:21
+   |
+LL | pub struct WeakOnce<T>();
+   |                     ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
+
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+  --> $DIR/inline-tainted-body.rs:11:35
+   |
+LL |     extern "rust-call" fn try_get(&self) -> Option<Arc<T>> {}
+   |                                   ^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/inline-tainted-body.rs:11:45
+   |
+LL |     extern "rust-call" fn try_get(&self) -> Option<Arc<T>> {}
+   |                           -------           ^^^^^^^^^^^^^^ expected `Option<Arc<T>>`, found `()`
+   |                           |
+   |                           implicitly returns `()` as its body has no tail or `return` expression
+   |
+   = note:   expected enum `Option<Arc<T>>`
+           found unit type `()`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0392.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/print-calling-conventions.rs b/tests/ui/print-calling-conventions.rs
new file mode 100644
index 00000000000..302ed088142
--- /dev/null
+++ b/tests/ui/print-calling-conventions.rs
@@ -0,0 +1,2 @@
+//@ compile-flags: --print calling-conventions
+//@ build-pass
diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout
new file mode 100644
index 00000000000..da67a57f420
--- /dev/null
+++ b/tests/ui/print-calling-conventions.stdout
@@ -0,0 +1,34 @@
+C
+C-cmse-nonsecure-call
+C-unwind
+Rust
+aapcs
+aapcs-unwind
+avr-interrupt
+avr-non-blocking-interrupt
+cdecl
+cdecl-unwind
+efiapi
+fastcall
+fastcall-unwind
+msp430-interrupt
+ptx-kernel
+riscv-interrupt-m
+riscv-interrupt-s
+rust-call
+rust-cold
+rust-intrinsic
+stdcall
+stdcall-unwind
+system
+system-unwind
+sysv64
+sysv64-unwind
+thiscall
+thiscall-unwind
+unadjusted
+vectorcall
+vectorcall-unwind
+win64
+win64-unwind
+x86-interrupt
diff --git a/tests/ui/process/println-with-broken-pipe.run.stderr b/tests/ui/process/println-with-broken-pipe.run.stderr
index a334c0ad204..f9d138a0424 100644
--- a/tests/ui/process/println-with-broken-pipe.run.stderr
+++ b/tests/ui/process/println-with-broken-pipe.run.stderr
@@ -1,3 +1,3 @@
-thread 'main' panicked at library/std/src/io/stdio.rs:LL:CC:
+thread 'main' panicked at std/src/io/stdio.rs:LL:CC:
 failed printing to stdout: Broken pipe (os error 32)
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/tests/ui/pub/pub-ident-struct-4.fixed b/tests/ui/pub/pub-ident-struct-4.fixed
index a62ece43ece..5fedbb72437 100644
--- a/tests/ui/pub/pub-ident-struct-4.fixed
+++ b/tests/ui/pub/pub-ident-struct-4.fixed
@@ -1,7 +1,6 @@
 //@ run-rustfix
 
-#[allow(dead_code)]
-pub struct T(String);
+pub struct T(#[allow(dead_code)] String);
 //~^ ERROR missing `struct` for struct definition
 
 fn main() {}
diff --git a/tests/ui/pub/pub-ident-struct-4.rs b/tests/ui/pub/pub-ident-struct-4.rs
index 0d56a31beaf..5c721c25a78 100644
--- a/tests/ui/pub/pub-ident-struct-4.rs
+++ b/tests/ui/pub/pub-ident-struct-4.rs
@@ -1,7 +1,6 @@
 //@ run-rustfix
 
-#[allow(dead_code)]
-pub T(String);
+pub T(#[allow(dead_code)] String);
 //~^ ERROR missing `struct` for struct definition
 
 fn main() {}
diff --git a/tests/ui/pub/pub-ident-struct-4.stderr b/tests/ui/pub/pub-ident-struct-4.stderr
index d3072464e05..04965a1a737 100644
--- a/tests/ui/pub/pub-ident-struct-4.stderr
+++ b/tests/ui/pub/pub-ident-struct-4.stderr
@@ -1,12 +1,12 @@
 error: missing `struct` for struct definition
-  --> $DIR/pub-ident-struct-4.rs:4:1
+  --> $DIR/pub-ident-struct-4.rs:3:1
    |
-LL | pub T(String);
+LL | pub T(#[allow(dead_code)] String);
    | ^^^^^
    |
 help: add `struct` here to parse `T` as a struct
    |
-LL | pub struct T(String);
+LL | pub struct T(#[allow(dead_code)] String);
    |     ++++++
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/reachable/unreachable-loop-patterns.rs b/tests/ui/reachable/unreachable-loop-patterns.rs
index 4294a18ba44..d074e3a6ece 100644
--- a/tests/ui/reachable/unreachable-loop-patterns.rs
+++ b/tests/ui/reachable/unreachable-loop-patterns.rs
@@ -1,6 +1,4 @@
 #![feature(never_type, never_type_fallback)]
-#![feature(min_exhaustive_patterns)]
-
 #![allow(unreachable_code)]
 #![deny(unreachable_patterns)]
 
diff --git a/tests/ui/reachable/unreachable-loop-patterns.stderr b/tests/ui/reachable/unreachable-loop-patterns.stderr
index bdd9b5ee411..9b7c2ba4acd 100644
--- a/tests/ui/reachable/unreachable-loop-patterns.stderr
+++ b/tests/ui/reachable/unreachable-loop-patterns.stderr
@@ -1,12 +1,12 @@
 error: unreachable pattern
-  --> $DIR/unreachable-loop-patterns.rs:18:9
+  --> $DIR/unreachable-loop-patterns.rs:16:9
    |
 LL |     for _ in unimplemented!() as Void {}
    |         ^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 note: the lint level is defined here
-  --> $DIR/unreachable-loop-patterns.rs:5:9
+  --> $DIR/unreachable-loop-patterns.rs:3:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/regions/regions-issue-21422.rs b/tests/ui/regions/regions-issue-21422.rs
index 67852a6f5de..54beed9b3ac 100644
--- a/tests/ui/regions/regions-issue-21422.rs
+++ b/tests/ui/regions/regions-issue-21422.rs
@@ -5,7 +5,6 @@
 
 //@ pretty-expanded FIXME #23616
 
-#[allow(dead_code)]
 pub struct P<'a> {
     _ptr: *const &'a u8,
 }
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.rs b/tests/ui/rfcs/rfc-0000-never_patterns/check.rs
index dc13dd05fa6..77f79003edc 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/check.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.rs
@@ -11,22 +11,22 @@ macro_rules! never {
 }
 
 fn no_arms_or_guards(x: Void) {
-    match None::<Void> {
+    match &None::<Void> {
         Some(!) => {}
         //~^ ERROR a never pattern is always unreachable
         None => {}
     }
-    match None::<Void> { //~ ERROR: `Some(!)` not covered
+    match &None::<Void> { //~ ERROR: `&Some(!)` not covered
         Some(!) if true,
         //~^ ERROR guard on a never pattern
         None => {}
     }
-    match None::<Void> { //~ ERROR: `Some(!)` not covered
+    match &None::<Void> { //~ ERROR: `&Some(!)` not covered
         Some(!) if true => {}
         //~^ ERROR a never pattern is always unreachable
         None => {}
     }
-    match None::<Void> {
+    match &None::<Void> {
         Some(never!()) => {}
         //~^ ERROR a never pattern is always unreachable
         None => {}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
index fbf7aa02ac2..4622ea59b54 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
@@ -31,40 +31,42 @@ LL |         Some(never!()) => {}
    |                           this will never be executed
    |                           help: remove this expression
 
-error[E0004]: non-exhaustive patterns: `Some(!)` not covered
+error[E0004]: non-exhaustive patterns: `&Some(!)` not covered
   --> $DIR/check.rs:19:11
    |
-LL |     match None::<Void> {
-   |           ^^^^^^^^^^^^ pattern `Some(!)` not covered
+LL |     match &None::<Void> {
+   |           ^^^^^^^^^^^^^ pattern `&Some(!)` not covered
    |
 note: `Option<Void>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
    = note: not covered
-   = note: the matched value is of type `Option<Void>`
+   = note: the matched value is of type `&Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
-LL +         Some(!)
+LL +         &Some(!)
    |
 
-error[E0004]: non-exhaustive patterns: `Some(!)` not covered
+error[E0004]: non-exhaustive patterns: `&Some(!)` not covered
   --> $DIR/check.rs:24:11
    |
-LL |     match None::<Void> {
-   |           ^^^^^^^^^^^^ pattern `Some(!)` not covered
+LL |     match &None::<Void> {
+   |           ^^^^^^^^^^^^^ pattern `&Some(!)` not covered
    |
 note: `Option<Void>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
    = note: not covered
-   = note: the matched value is of type `Option<Void>`
+   = note: the matched value is of type `&Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
-LL +         Some(!)
+LL +         &Some(!)
    |
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr
index 013a8b53a55..9e2ae2846d5 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr
@@ -1,5 +1,5 @@
 error: mismatched types
-  --> $DIR/typeck.rs:25:9
+  --> $DIR/typeck.rs:24:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -7,7 +7,7 @@ LL |         !,
    = note: the matched value is of type `()`
 
 error: mismatched types
-  --> $DIR/typeck.rs:29:9
+  --> $DIR/typeck.rs:28:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -15,7 +15,7 @@ LL |         !,
    = note: the matched value is of type `(i32, bool)`
 
 error: mismatched types
-  --> $DIR/typeck.rs:33:13
+  --> $DIR/typeck.rs:32:13
    |
 LL |         (_, !),
    |             ^ a never pattern must be used on an uninhabited type
@@ -23,7 +23,7 @@ LL |         (_, !),
    = note: the matched value is of type `bool`
 
 error: mismatched types
-  --> $DIR/typeck.rs:38:14
+  --> $DIR/typeck.rs:37:14
    |
 LL |         Some(!),
    |              ^ a never pattern must be used on an uninhabited type
@@ -31,7 +31,7 @@ LL |         Some(!),
    = note: the matched value is of type `i32`
 
 error: mismatched types
-  --> $DIR/typeck.rs:45:9
+  --> $DIR/typeck.rs:44:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -39,7 +39,7 @@ LL |         !,
    = note: the matched value is of type `()`
 
 error: mismatched types
-  --> $DIR/typeck.rs:52:9
+  --> $DIR/typeck.rs:51:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -47,7 +47,7 @@ LL |         !,
    = note: the matched value is of type `Option<Void>`
 
 error: mismatched types
-  --> $DIR/typeck.rs:57:9
+  --> $DIR/typeck.rs:56:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -55,7 +55,7 @@ LL |         !,
    = note: the matched value is of type `[Void]`
 
 error: mismatched types
-  --> $DIR/typeck.rs:63:9
+  --> $DIR/typeck.rs:62:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs
index 8300f953dc1..bf74b282f6c 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs
@@ -2,7 +2,6 @@
 //@[pass] check-pass
 //@[fail] check-fail
 #![feature(never_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![allow(incomplete_features)]
 
 #[derive(Copy, Clone)]
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr
index a875041d89c..d78f4a5f6eb 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/unreachable.rs:17:9
+  --> $DIR/unreachable.rs:16:9
    |
 LL |         Err(!),
    |         ^^^^^^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 note: the lint level is defined here
-  --> $DIR/unreachable.rs:7:9
+  --> $DIR/unreachable.rs:6:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:20:19
+  --> $DIR/unreachable.rs:19:19
    |
 LL |     let (Ok(_x) | Err(!)) = res_void;
    |                   ^^^^^^
@@ -20,7 +20,7 @@ LL |     let (Ok(_x) | Err(!)) = res_void;
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:22:12
+  --> $DIR/unreachable.rs:21:12
    |
 LL |     if let Err(!) = res_void {}
    |            ^^^^^^
@@ -28,7 +28,7 @@ LL |     if let Err(!) = res_void {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:24:24
+  --> $DIR/unreachable.rs:23:24
    |
 LL |     if let (Ok(true) | Err(!)) = res_void {}
    |                        ^^^^^^
@@ -36,7 +36,7 @@ LL |     if let (Ok(true) | Err(!)) = res_void {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:26:23
+  --> $DIR/unreachable.rs:25:23
    |
 LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
    |                       ^^^^^^
@@ -44,7 +44,7 @@ LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:30:18
+  --> $DIR/unreachable.rs:29:18
    |
 LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
    |                  ^^^^^^
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.normal.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.normal.stderr
new file mode 100644
index 00000000000..a3bf8e80ece
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.normal.stderr
@@ -0,0 +1,44 @@
+error: unreachable pattern
+  --> $DIR/unreachable.rs:16:9
+   |
+LL |         Err(!),
+   |         ^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unreachable.rs:6:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:19:19
+   |
+LL |     let (Ok(_x) | Err(!)) = res_void;
+   |                   ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:21:12
+   |
+LL |     if let Err(!) = res_void {}
+   |            ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:23:24
+   |
+LL |     if let (Ok(true) | Err(!)) = res_void {}
+   |                        ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:25:23
+   |
+LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
+   |                       ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:29:18
+   |
+LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
+   |                  ^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
index 4d20c67cf0f..f68da4aa173 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
@@ -1,8 +1,5 @@
-//@ revisions: normal exh_pats
-//@[normal] check-pass
 #![feature(never_patterns)]
 #![allow(incomplete_features)]
-#![cfg_attr(exh_pats, feature(min_exhaustive_patterns))]
 #![allow(dead_code, unreachable_code)]
 #![deny(unreachable_patterns)]
 
@@ -15,17 +12,17 @@ fn main() {
     match res_void {
         Ok(_x) => {}
         Err(!),
-        //[exh_pats]~^ ERROR unreachable
+        //~^ ERROR unreachable
     }
     let (Ok(_x) | Err(!)) = res_void;
-    //[exh_pats]~^ ERROR unreachable
+    //~^ ERROR unreachable
     if let Err(!) = res_void {}
-    //[exh_pats]~^ ERROR unreachable
+    //~^ ERROR unreachable
     if let (Ok(true) | Err(!)) = res_void {}
-    //[exh_pats]~^ ERROR unreachable
+    //~^ ERROR unreachable
     for (Ok(mut _x) | Err(!)) in [res_void] {}
-    //[exh_pats]~^ ERROR unreachable
+    //~^ ERROR unreachable
 }
 
 fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
-//[exh_pats]~^ ERROR unreachable
+//~^ ERROR unreachable
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr
new file mode 100644
index 00000000000..79b640d9f41
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr
@@ -0,0 +1,55 @@
+error: unreachable pattern
+  --> $DIR/unreachable.rs:14:9
+   |
+LL |         Err(!),
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+note: the lint level is defined here
+  --> $DIR/unreachable.rs:4:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:17:19
+   |
+LL |     let (Ok(_x) | Err(!)) = res_void;
+   |                   ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:19:12
+   |
+LL |     if let Err(!) = res_void {}
+   |            ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:21:24
+   |
+LL |     if let (Ok(true) | Err(!)) = res_void {}
+   |                        ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:23:23
+   |
+LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
+   |                       ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:27:18
+   |
+LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
+   |                  ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
index 8f090fe886a..d81896eba19 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 #![feature(never_type)]
 
 #[non_exhaustive]
@@ -28,24 +29,24 @@ pub struct IndirectUninhabitedVariants(UninhabitedVariants);
 struct A;
 
 // This test checks that an empty match on a non-exhaustive uninhabited type through a level of
-// indirection from the defining crate will not compile without `#![feature(exhaustive_patterns)]`.
+// indirection from the defining crate compiles.
 
 fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
     x: IndirectUninhabitedVariants,
 ) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
deleted file mode 100644
index c1219054140..00000000000
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
+++ /dev/null
@@ -1,79 +0,0 @@
-error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
-  --> $DIR/indirect_match_same_crate.rs:34:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `IndirectUninhabitedEnum` defined here
-  --> $DIR/indirect_match_same_crate.rs:20:12
-   |
-LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
-   |            ^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `IndirectUninhabitedEnum`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
-  --> $DIR/indirect_match_same_crate.rs:38:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `IndirectUninhabitedStruct` defined here
-  --> $DIR/indirect_match_same_crate.rs:22:12
-   |
-LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `IndirectUninhabitedStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
-  --> $DIR/indirect_match_same_crate.rs:42:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `IndirectUninhabitedTupleStruct` defined here
-  --> $DIR/indirect_match_same_crate.rs:24:12
-   |
-LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `IndirectUninhabitedTupleStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
-  --> $DIR/indirect_match_same_crate.rs:48:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `IndirectUninhabitedVariants` defined here
-  --> $DIR/indirect_match_same_crate.rs:26:12
-   |
-LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `IndirectUninhabitedVariants`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
index c40a2676e84..dd9a570522a 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
@@ -1,6 +1,5 @@
 //@ aux-build:uninhabited.rs
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 extern crate uninhabited;
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
index ef97c1fa17f..745b196a0e3 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:22:11
    |
 LL |     match x {}
    |           ^
@@ -18,7 +18,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:26:11
    |
 LL |     match x {}
    |           ^
@@ -37,7 +37,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:30:11
    |
 LL |     match x {}
    |           ^
@@ -56,7 +56,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:36:11
    |
 LL |     match x {}
    |           ^
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
index efaec0ebdbe..32f5f504136 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
@@ -1,7 +1,6 @@
 //@ check-pass
 
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 #[non_exhaustive]
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
index ebbdfba15f3..04f7fe26b5a 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 #![feature(never_type)]
 
 #[non_exhaustive]
@@ -27,15 +28,15 @@ fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
 }
 
 fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
deleted file mode 100644
index 7a12aca8520..00000000000
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
+++ /dev/null
@@ -1,64 +0,0 @@
-error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
-  --> $DIR/match_same_crate.rs:30:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `UninhabitedStruct` defined here
-  --> $DIR/match_same_crate.rs:8:12
-   |
-LL | pub struct UninhabitedStruct {
-   |            ^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
-  --> $DIR/match_same_crate.rs:34:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `UninhabitedTupleStruct` defined here
-  --> $DIR/match_same_crate.rs:13:12
-   |
-LL | pub struct UninhabitedTupleStruct(!);
-   |            ^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedTupleStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-  --> $DIR/match_same_crate.rs:38:11
-   |
-LL |     match x {}
-   |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-   |
-note: `UninhabitedVariants` defined here
-  --> $DIR/match_same_crate.rs:15:10
-   |
-LL | pub enum UninhabitedVariants {
-   |          ^^^^^^^^^^^^^^^^^^^
-LL |     #[non_exhaustive] Tuple(!),
-   |                       ----- not covered
-LL |     #[non_exhaustive] Struct { x: ! }
-   |                       ------ not covered
-   = note: the matched value is of type `UninhabitedVariants`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
-   |
-LL ~     match x {
-LL +         UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
-LL ~     }
-   |
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
index 69b15fca0b7..108cac7099e 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
@@ -1,6 +1,5 @@
 //@ aux-build:uninhabited.rs
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 extern crate uninhabited;
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
index 19e2546b0da..0c8b14ab69d 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:22:11
+  --> $DIR/match_with_exhaustive_patterns.rs:21:11
    |
 LL |     match x {}
    |           ^
@@ -18,7 +18,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:26:11
+  --> $DIR/match_with_exhaustive_patterns.rs:25:11
    |
 LL |     match x {}
    |           ^
@@ -37,7 +37,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:30:11
+  --> $DIR/match_with_exhaustive_patterns.rs:29:11
    |
 LL |     match x {}
    |           ^
@@ -56,7 +56,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-  --> $DIR/match_with_exhaustive_patterns.rs:34:11
+  --> $DIR/match_with_exhaustive_patterns.rs:33:11
    |
 LL |     match x {}
    |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
index bbc5d03d612..468703c78e0 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
@@ -1,7 +1,6 @@
 //@ check-pass
 
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 #[non_exhaustive]
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
index 0007614988c..be55ad51578 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
@@ -1,7 +1,6 @@
 //@ aux-build:uninhabited.rs
 //@ build-pass (FIXME(62277): could be check-pass?)
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 
 extern crate uninhabited;
 
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
index 898be87ccca..1194d7b858d 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
@@ -1,5 +1,4 @@
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 #[non_exhaustive]
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
index d5192a70ed5..c399bb9083f 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:52:9
+  --> $DIR/patterns_same_crate.rs:51:9
    |
 LL |         Some(_x) => (),
    |         ^^^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:57:9
+  --> $DIR/patterns_same_crate.rs:56:9
    |
 LL |         Some(_x) => (),
    |         ^^^^^^^^
@@ -20,7 +20,7 @@ LL |         Some(_x) => (),
    = note: this pattern matches no values because `UninhabitedVariants` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:61:15
+  --> $DIR/patterns_same_crate.rs:60:15
    |
 LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabite
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:65:15
+  --> $DIR/patterns_same_crate.rs:64:15
    |
 LL |     while let Some(_x) = uninhabited_struct() {
    |               ^^^^^^^^
@@ -36,7 +36,7 @@ LL |     while let Some(_x) = uninhabited_struct() {
    = note: this pattern matches no values because `UninhabitedStruct` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:68:15
+  --> $DIR/patterns_same_crate.rs:67:15
    |
 LL |     while let Some(_x) = uninhabited_tuple_struct() {
    |               ^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
index de002ef71d7..fec4e75290f 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
@@ -34,6 +34,7 @@ fn foo() {
 
 #[target_feature(enable = "sse2")]
 fn bar() {
+    sse2();
     avx_bmi2();
     //~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
     Quux.avx_bmi2();
@@ -43,7 +44,6 @@ fn bar() {
 #[target_feature(enable = "avx")]
 fn baz() {
     sse2();
-    //~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
     avx_bmi2();
     //~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
     Quux.avx_bmi2();
@@ -54,7 +54,8 @@ fn baz() {
 #[target_feature(enable = "bmi2")]
 fn qux() {
     sse2();
-    //~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
+    avx_bmi2();
+    Quux.avx_bmi2();
 }
 
 const _: () = sse2();
@@ -64,8 +65,6 @@ const _: () = sse2_and_fxsr();
 //~^ ERROR call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe
 
 #[deny(unsafe_op_in_unsafe_fn)]
-#[target_feature(enable = "avx")]
-#[target_feature(enable = "bmi2")]
 unsafe fn needs_unsafe_block() {
     sse2();
     //~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
index 537819ab859..1ddf05b40a6 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
@@ -24,7 +24,7 @@ LL |     Quux.avx_bmi2();
    = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
 
 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:37:5
+  --> $DIR/safe-calls.rs:38:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -32,22 +32,13 @@ LL |     avx_bmi2();
    = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
 
 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:39:5
+  --> $DIR/safe-calls.rs:40:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
    |
    = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
 
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:45:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
   --> $DIR/safe-calls.rs:47:5
    |
@@ -65,16 +56,7 @@ LL |     Quux.avx_bmi2();
    = help: in order for the call to be safe, the context requires the following additional target feature: bmi2
 
 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:56:5
-   |
-LL |     sse2();
-   |     ^^^^^^ call to function with `#[target_feature]`
-   |
-   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
-   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
-
-error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:60:15
+  --> $DIR/safe-calls.rs:61:15
    |
 LL | const _: () = sse2();
    |               ^^^^^^ call to function with `#[target_feature]`
@@ -83,7 +65,7 @@ LL | const _: () = sse2();
    = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
 
 error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:63:15
+  --> $DIR/safe-calls.rs:64:15
    |
 LL | const _: () = sse2_and_fxsr();
    |               ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -92,7 +74,7 @@ LL | const _: () = sse2_and_fxsr();
    = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
 
 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block
-  --> $DIR/safe-calls.rs:70:5
+  --> $DIR/safe-calls.rs:69:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -101,16 +83,16 @@ LL |     sse2();
    = help: in order for the call to be safe, the context requires the following additional target feature: sse2
    = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
 note: an unsafe function restricts its caller, but its body is safe by default
-  --> $DIR/safe-calls.rs:69:1
+  --> $DIR/safe-calls.rs:68:1
    |
 LL | unsafe fn needs_unsafe_block() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: the lint level is defined here
-  --> $DIR/safe-calls.rs:66:8
+  --> $DIR/safe-calls.rs:67:8
    |
 LL | #[deny(unsafe_op_in_unsafe_fn)]
    |        ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
index 9d1ca5dbf2c..b451555ec3c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
@@ -40,7 +40,7 @@ error: `~const` can only be applied to `#[const_trait]` traits
 LL | const fn a<T: ~const Destruct>(_: T) {}
    |                      ^^^^^^^^
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-drop.rs:54:5
    |
 LL |     #[const_trait]
@@ -49,7 +49,7 @@ LL |     pub trait SomeTrait {
 LL |         fn foo();
    |               - expected 0 const parameters
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-drop.rs:54:5
    |
 LL |     #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
index 2f93f9a6743..296614f7fd0 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
@@ -40,7 +40,7 @@ error: `~const` can only be applied to `#[const_trait]` traits
 LL | const fn a<T: ~const Destruct>(_: T) {}
    |                      ^^^^^^^^
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-drop.rs:54:5
    |
 LL |     #[const_trait]
@@ -49,7 +49,7 @@ LL |     pub trait SomeTrait {
 LL |         fn foo();
    |               - expected 0 const parameters
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-drop.rs:54:5
    |
 LL |     #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
index b4c4cf0a890..7643697874f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-bound-non-const-specialized-bound.rs:16:1
    |
 LL | #[const_trait]
@@ -16,7 +16,7 @@ LL | |     T: Foo, //FIXME ~ ERROR missing `~const` qualifier
 LL | |     T: Specialize,
    | |__________________^
 
-error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1
    |
 LL | #[const_trait]
@@ -25,7 +25,7 @@ LL | trait Baz {
 LL |     fn baz();
    |           - expected 0 const parameters
 
-error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
index cabf201405f..9b2ae8d739c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-const-specialized.rs:10:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | trait Value {
 LL |     fn value() -> u32;
    |             - expected 0 const parameters
 
-error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-const-specialized.rs:10:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr
index 52c8708f2c8..18a25045f4b 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/default-keyword.rs:7:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr
index 1aa34637ca4..ecdc7b930e6 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | trait Foo {
 LL |     fn foo();
    |           - expected 0 const parameters
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1
    |
 LL | #[const_trait]
@@ -18,7 +18,7 @@ LL |     fn foo();
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1
    |
 LL | #[const_trait]
@@ -27,7 +27,7 @@ LL | trait Bar {
 LL |     fn bar() {}
    |           - expected 0 const parameters
 
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr
index 0e0f391b086..6679bb46537 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | trait Bar {
 LL |     fn bar();
    |           - expected 0 const parameters
 
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1
    |
 LL | #[const_trait]
@@ -18,7 +18,7 @@ LL |     fn bar();
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1
    |
 LL | #[const_trait]
@@ -27,7 +27,7 @@ LL | trait Baz {
 LL |     fn baz();
    |           - expected 0 const parameters
 
-error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
index d49beb93259..7f363922947 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/non-const-default-const-specialized.rs:9:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | trait Value {
 LL |     fn value() -> u32;
    |             - expected 0 const parameters
 
-error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/non-const-default-const-specialized.rs:9:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
index d082cd6de60..bf273f349b4 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/specializing-constness-2.rs:9:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | pub trait A {
 LL |     fn a() -> u32;
    |         - expected 0 const parameters
 
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/specializing-constness-2.rs:9:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/auxiliary/edition-lint-infer-outlives-macro.rs
index d45fa10f022..d45fa10f022 100644
--- a/tests/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/auxiliary/edition-lint-infer-outlives-macro.rs
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed
index 435857224ac..435857224ac 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs
index 6c879231a16..6c879231a16 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.stderr
index d684911be39..d684911be39 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.stderr
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.rs
index d2254acb33f..d2254acb33f 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.rs
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.stderr
index 1f4190665b9..1f4190665b9 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.stderr
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.fixed
index c4948051c18..c4948051c18 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.fixed
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.rs
index c80e91ca12c..c80e91ca12c 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.rs
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.rs
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.stderr
index dbf301fd8a1..dbf301fd8a1 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.stderr
diff --git a/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.fixed b/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.fixed
new file mode 100644
index 00000000000..7b9fac8f408
--- /dev/null
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.fixed
@@ -0,0 +1,41 @@
+//@ run-rustfix
+//@ check-pass
+#![deny(explicit_outlives_requirements)]
+
+pub trait TypeCx {
+    type Ty;
+}
+
+pub struct Pat<Cx: TypeCx> {
+    pub ty: Cx::Ty,
+}
+
+// Simple recursive case: no warning
+pub struct MyTypeContextSimpleRecursive<'thir, 'tcx: 'thir> {
+    pub pat: Pat<MyTypeContextSimpleRecursive<'thir, 'tcx>>,
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextSimpleRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+// Non-recursive case: we want a warning
+pub struct MyTypeContextNotRecursive<'thir, 'tcx: 'thir> {
+    pub tcx: &'tcx (),
+    pub thir: &'thir (),
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextNotRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+
+// Mixed-recursive case: we want a warning
+pub struct MyTypeContextMixedRecursive<'thir, 'tcx: 'thir> {
+    pub pat: Pat<MyTypeContextMixedRecursive<'thir, 'tcx>>,
+    pub tcx: &'tcx (),
+    pub thir: &'thir (),
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextMixedRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+fn main() {}
diff --git a/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.rs
new file mode 100644
index 00000000000..7b9fac8f408
--- /dev/null
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.rs
@@ -0,0 +1,41 @@
+//@ run-rustfix
+//@ check-pass
+#![deny(explicit_outlives_requirements)]
+
+pub trait TypeCx {
+    type Ty;
+}
+
+pub struct Pat<Cx: TypeCx> {
+    pub ty: Cx::Ty,
+}
+
+// Simple recursive case: no warning
+pub struct MyTypeContextSimpleRecursive<'thir, 'tcx: 'thir> {
+    pub pat: Pat<MyTypeContextSimpleRecursive<'thir, 'tcx>>,
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextSimpleRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+// Non-recursive case: we want a warning
+pub struct MyTypeContextNotRecursive<'thir, 'tcx: 'thir> {
+    pub tcx: &'tcx (),
+    pub thir: &'thir (),
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextNotRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+
+// Mixed-recursive case: we want a warning
+pub struct MyTypeContextMixedRecursive<'thir, 'tcx: 'thir> {
+    pub pat: Pat<MyTypeContextMixedRecursive<'thir, 'tcx>>,
+    pub tcx: &'tcx (),
+    pub thir: &'thir (),
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextMixedRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+fn main() {}
diff --git a/tests/ui/rust-2024/safe-outside-extern.rs b/tests/ui/rust-2024/safe-outside-extern.rs
index 6773df5ef03..674b78dc571 100644
--- a/tests/ui/rust-2024/safe-outside-extern.rs
+++ b/tests/ui/rust-2024/safe-outside-extern.rs
@@ -1,29 +1,21 @@
-//@ revisions: gated ungated
-#![cfg_attr(gated, feature(unsafe_extern_blocks))]
-
 safe fn foo() {}
 //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
-//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
 
 safe static FOO: i32 = 1;
 //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
-//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
 
 trait Foo {
     safe fn foo();
     //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
-    //[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
 }
 
 impl Foo for () {
     safe fn foo() {}
     //~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
-    //[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
 }
 
 type FnPtr = safe fn(i32, i32) -> i32;
 //~^ ERROR: function pointers cannot be declared with `safe` safety qualifier
-//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
 
 unsafe static LOL: u8 = 0;
 //~^ ERROR: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block
diff --git a/tests/ui/rust-2024/safe-outside-extern.stderr b/tests/ui/rust-2024/safe-outside-extern.stderr
new file mode 100644
index 00000000000..19d7c5fde0b
--- /dev/null
+++ b/tests/ui/rust-2024/safe-outside-extern.stderr
@@ -0,0 +1,38 @@
+error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
+  --> $DIR/safe-outside-extern.rs:1:1
+   |
+LL | safe fn foo() {}
+   | ^^^^^^^^^^^^^^^^
+
+error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
+  --> $DIR/safe-outside-extern.rs:4:1
+   |
+LL | safe static FOO: i32 = 1;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
+  --> $DIR/safe-outside-extern.rs:8:5
+   |
+LL |     safe fn foo();
+   |     ^^^^^^^^^^^^^^
+
+error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
+  --> $DIR/safe-outside-extern.rs:13:5
+   |
+LL |     safe fn foo() {}
+   |     ^^^^^^^^^^^^^^^^
+
+error: function pointers cannot be declared with `safe` safety qualifier
+  --> $DIR/safe-outside-extern.rs:17:14
+   |
+LL | type FnPtr = safe fn(i32, i32) -> i32;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block
+  --> $DIR/safe-outside-extern.rs:20:1
+   |
+LL | unsafe static LOL: u8 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr
index 3a99caa719b..77554da10e6 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr
@@ -1,5 +1,5 @@
 error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block
-  --> $DIR/extern-items-unsafe.rs:14:5
+  --> $DIR/extern-items-unsafe.rs:12:5
    |
 LL |     test1(TEST1);
    |     ^^^^^^^^^^^^ call to unsafe function
@@ -7,7 +7,7 @@ LL |     test1(TEST1);
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/extern-items-unsafe.rs:14:11
+  --> $DIR/extern-items-unsafe.rs:12:11
    |
 LL |     test1(TEST1);
    |           ^^^^^ use of extern static
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr
index fcf937b7ac5..33b752782d5 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr
@@ -1,5 +1,5 @@
 error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block
-  --> $DIR/extern-items-unsafe.rs:14:5
+  --> $DIR/extern-items-unsafe.rs:12:5
    |
 LL |     test1(TEST1);
    |     ^^^^^^^^^^^^ call to unsafe function
@@ -7,7 +7,7 @@ LL |     test1(TEST1);
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe block
-  --> $DIR/extern-items-unsafe.rs:14:11
+  --> $DIR/extern-items-unsafe.rs:12:11
    |
 LL |     test1(TEST1);
    |           ^^^^^ use of extern static
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs
index ad569a256db..721e07acca5 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs
@@ -3,8 +3,6 @@
 //@[edition2024] edition:2024
 //@[edition2024] compile-flags: -Zunstable-options
 
-#![feature(unsafe_extern_blocks)]
-
 unsafe extern "C" {
     static TEST1: i32;
     fn test1(i: i32);
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr
index d456cfc6829..8ef7c2caf21 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr
@@ -1,5 +1,5 @@
 error: extern blocks must be unsafe
-  --> $DIR/extern-items.rs:9:1
+  --> $DIR/extern-items.rs:7:1
    |
 LL | / extern "C" {
 LL | |
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs
index 16fa1bbb8a4..08805c36347 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs
@@ -4,8 +4,6 @@
 //@[edition2024] edition:2024
 //@[edition2024] compile-flags: -Zunstable-options
 
-#![feature(unsafe_extern_blocks)]
-
 extern "C" {
     //[edition2024]~^ ERROR extern blocks must be unsafe
     static TEST1: i32;
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs
index 57c03e4d896..67df8c14b39 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs
@@ -1,6 +1,3 @@
-//@ revisions: gated ungated
-#![cfg_attr(gated, feature(unsafe_extern_blocks))]
-
 trait Bar {}
 safe impl Bar for () { }
 //~^ ERROR expected one of `!` or `::`, found keyword `impl`
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.stderr
index 80e7a45f57e..f1021726b18 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.stderr
@@ -1,5 +1,5 @@
 error: expected one of `!` or `::`, found keyword `impl`
-  --> $DIR/safe-impl-trait.rs:5:6
+  --> $DIR/safe-impl-trait.rs:2:6
    |
 LL | safe impl Bar for () { }
    |      ^^^^ expected one of `!` or `::`
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs
index 74cd5621fce..b0b8a8b012a 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs
@@ -4,8 +4,6 @@
 //@[edition2024] compile-flags: -Zunstable-options
 //@ check-pass
 
-#![feature(unsafe_extern_blocks)]
-
 unsafe extern "C" {
     safe static TEST1: i32;
     safe fn test1(i: i32);
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs
index e73cb45b188..52773b4cbbb 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs
@@ -1,6 +1,3 @@
-//@ revisions: gated ungated
-#![cfg_attr(gated, feature(unsafe_extern_blocks))]
-
 safe trait Foo {}
 //~^ ERROR expected one of `!` or `::`, found keyword `trait`
 
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr
new file mode 100644
index 00000000000..1733336a797
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found keyword `trait`
+  --> $DIR/safe-trait.rs:1:6
+   |
+LL | safe trait Foo {}
+   |      ^^^^^ expected one of `!` or `::`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr
index e90613357b1..93797987286 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr
@@ -1,5 +1,5 @@
 error: items in unadorned `extern` blocks cannot have safety qualifiers
-  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
+  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:5
    |
 LL |     safe static TEST1: i32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL | unsafe extern "C" {
    | ++++++
 
 error: items in unadorned `extern` blocks cannot have safety qualifiers
-  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5
+  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
    |
 LL |     safe fn test1(i: i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr
index 1207ee158cc..e9db6006c0b 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr
@@ -1,5 +1,5 @@
 error: extern blocks must be unsafe
-  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:1
+  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:6:1
    |
 LL | / extern "C" {
 LL | |
@@ -11,7 +11,7 @@ LL | | }
    | |_^
 
 error: items in unadorned `extern` blocks cannot have safety qualifiers
-  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
+  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:5
    |
 LL |     safe static TEST1: i32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL | unsafe extern "C" {
    | ++++++
 
 error: items in unadorned `extern` blocks cannot have safety qualifiers
-  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5
+  --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
    |
 LL |     safe fn test1(i: i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs
index 11f55cb195f..4badb50b267 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs
@@ -3,8 +3,6 @@
 //@[edition2024] edition:2024
 //@[edition2024] compile-flags: -Zunstable-options
 
-#![feature(unsafe_extern_blocks)]
-
 extern "C" {
     //[edition2024]~^ ERROR extern blocks must be unsafe
     safe static TEST1: i32;
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed
index 10c19759d8a..f686809615f 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed
@@ -1,6 +1,5 @@
 //@ run-rustfix
 
-#![feature(unsafe_extern_blocks)]
 #![deny(missing_unsafe_on_extern)]
 #![allow(unused)]
 
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs
index b81e52ddc58..00f1cbdab54 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs
@@ -1,6 +1,5 @@
 //@ run-rustfix
 
-#![feature(unsafe_extern_blocks)]
 #![deny(missing_unsafe_on_extern)]
 #![allow(unused)]
 
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr
index 0a3c2cd25e3..bb1d068ceb9 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr
@@ -1,5 +1,5 @@
 error: extern blocks should be unsafe
-  --> $DIR/unsafe-extern-suggestion.rs:7:1
+  --> $DIR/unsafe-extern-suggestion.rs:6:1
    |
 LL |   extern "C" {
    |   ^
@@ -16,7 +16,7 @@ LL | | }
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
    = note: for more information, see issue #123743 <https://github.com/rust-lang/rust/issues/123743>
 note: the lint level is defined here
-  --> $DIR/unsafe-extern-suggestion.rs:4:9
+  --> $DIR/unsafe-extern-suggestion.rs:3:9
    |
 LL | #![deny(missing_unsafe_on_extern)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr
index 8bb7ffefeea..e3626bb497e 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr
@@ -1,5 +1,5 @@
 error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-items.rs:20:5
+  --> $DIR/unsafe-items.rs:18:5
    |
 LL |     test1(TEST1);
    |     ^^^^^^^^^^^^ call to unsafe function
@@ -7,7 +7,7 @@ LL |     test1(TEST1);
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-items.rs:20:11
+  --> $DIR/unsafe-items.rs:18:11
    |
 LL |     test1(TEST1);
    |           ^^^^^ use of extern static
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr
index 9a30142a632..89bc501b7b5 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr
@@ -1,5 +1,5 @@
 error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block
-  --> $DIR/unsafe-items.rs:20:5
+  --> $DIR/unsafe-items.rs:18:5
    |
 LL |     test1(TEST1);
    |     ^^^^^^^^^^^^ call to unsafe function
@@ -7,7 +7,7 @@ LL |     test1(TEST1);
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe block
-  --> $DIR/unsafe-items.rs:20:11
+  --> $DIR/unsafe-items.rs:18:11
    |
 LL |     test1(TEST1);
    |           ^^^^^ use of extern static
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs
index 9066953abc6..dc2bae892a9 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs
@@ -3,8 +3,6 @@
 //@[edition2024] edition:2024
 //@[edition2024] compile-flags: -Zunstable-options
 
-#![feature(unsafe_extern_blocks)]
-
 unsafe extern "C" {
     unsafe static TEST1: i32;
     unsafe fn test1(i: i32);
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed
index 2ff595cc44d..857d34eef85 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed
@@ -1,6 +1,5 @@
 //@ run-rustfix
 
-#![feature(unsafe_extern_blocks)]
 #![allow(dead_code)]
 
 unsafe extern "C" {
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs
index 6fe43f7a5b4..edab9850d79 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs
@@ -1,6 +1,5 @@
 //@ run-rustfix
 
-#![feature(unsafe_extern_blocks)]
 #![allow(dead_code)]
 
 extern "C" {
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr
index 05d23d001ad..073245e650b 100644
--- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr
@@ -1,5 +1,5 @@
 error: items in unadorned `extern` blocks cannot have safety qualifiers
-  --> $DIR/unsafe-on-extern-block-issue-126756.rs:7:5
+  --> $DIR/unsafe-on-extern-block-issue-126756.rs:6:5
    |
 LL |     unsafe fn foo();
    |     ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/sanitizer/cfi-can-reveal-opaques.rs b/tests/ui/sanitizer/cfi-can-reveal-opaques.rs
new file mode 100644
index 00000000000..55988a62a8c
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-can-reveal-opaques.rs
@@ -0,0 +1,44 @@
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
+//@ no-prefer-dynamic
+//@ only-x86_64-unknown-linux-gnu
+//@ build-pass
+
+// See comment below for why this test exists.
+
+trait Tr<U> {
+    type Projection;
+}
+
+impl<F, U> Tr<U> for F
+where
+    F: Fn() -> U
+{
+    type Projection = U;
+}
+
+fn test<B: Tr<U>, U>(b: B) -> B::Projection
+{
+    todo!()
+}
+
+fn main() {
+    fn rpit_fn() -> impl Sized {}
+
+    // When CFI runs, it tries to compute the signature of the call. This
+    // ends up giving us a signature of:
+    //     `fn test::<rpit_fn, ()>() -> <rpit_fn as Tr<()>>::Projection`,
+    // where `rpit_fn` is the ZST FnDef for the function. However, we were
+    // previously using a Reveal::UserFacing param-env. This means that the
+    // `<rpit_fn as Tr<()>>::Projection` return type is impossible to normalize,
+    // since it would require proving `rpit_fn: Fn() -> ()`, but we cannot
+    // prove that the `impl Sized` opaque is `()` with a user-facing param-env.
+    // This leads to a normalization error, and then an ICE.
+    //
+    // Side-note:
+    // So why is the second generic of `test` "`()`", and not the
+    // `impl Sized` since we inferred it from the return type of `rpit_fn`
+    // during typeck? Well, that's because we're using the generics from the
+    // terminator of the MIR, which has had the RevealAll pass performed on it.
+    let _ = test(rpit_fn);
+}
diff --git a/tests/ui/short-error-format.stderr b/tests/ui/short-error-format.stderr
index 8a22d673b98..1a4a6d4df88 100644
--- a/tests/ui/short-error-format.stderr
+++ b/tests/ui/short-error-format.stderr
@@ -1,3 +1,3 @@
-$DIR/short-error-format.rs:6:9: error[E0308]: mismatched types
-$DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for type `u32` in the current scope
+$DIR/short-error-format.rs:6:9: error[E0308]: mismatched types: expected `u32`, found `String`
+$DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for type `u32` in the current scope: method not found in `u32`
 error: aborting due to 2 previous errors
diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index e39138983c6..643f1de3e8d 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:6:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | pub unsafe trait Sup {
 LL |     fn foo() -> u32;
    |           - expected 0 const parameters
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:6:1
    |
 LL | #[const_trait]
@@ -36,7 +36,7 @@ error: `~const` can only be applied to `#[const_trait]` traits
 LL | impl<T: ~const Default + ~const Sub> const A for T {
    |                ^^^^^^^
 
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:29:1
    |
 LL | #[const_trait]
@@ -45,7 +45,7 @@ LL | pub trait A {
 LL |     fn a() -> u32;
    |         - expected 0 const parameters
 
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:29:1
    |
 LL | #[const_trait]
@@ -56,7 +56,7 @@ LL |     fn a() -> u32;
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:29:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/static/static-lifetime.rs b/tests/ui/static/static-lifetime.rs
index ce1eeb6105f..a861a2ffeda 100644
--- a/tests/ui/static/static-lifetime.rs
+++ b/tests/ui/static/static-lifetime.rs
@@ -1,6 +1,7 @@
 pub trait Arbitrary: Sized + 'static {}
 
 impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound
+//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter `'a`
 
 fn main() {
 }
diff --git a/tests/ui/static/static-lifetime.stderr b/tests/ui/static/static-lifetime.stderr
index 8c9434ce3cb..7a956dbfeef 100644
--- a/tests/ui/static/static-lifetime.stderr
+++ b/tests/ui/static/static-lifetime.stderr
@@ -11,6 +11,32 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
    |      ^^
    = note: but lifetime parameter must outlive the static lifetime
 
-error: aborting due to 1 previous error
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/static-lifetime.rs:3:34
+   |
+LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/static-lifetime.rs:3:6
+   |
+LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   |      ^^
+note: ...so that the types are compatible
+  --> $DIR/static-lifetime.rs:3:34
+   |
+LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected `<Cow<'a, A> as Arbitrary>`
+              found `<Cow<'_, A> as Arbitrary>`
+   = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that the declared lifetime parameter bounds are satisfied
+  --> $DIR/static-lifetime.rs:3:34
+   |
+LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0478`.
+Some errors have detailed explanations: E0478, E0495.
+For more information about an error, try `rustc --explain E0478`.
diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.rs b/tests/ui/statics/unsizing-wfcheck-issue-127299.rs
new file mode 100644
index 00000000000..cd15be54ec7
--- /dev/null
+++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.rs
@@ -0,0 +1,17 @@
+// This ensures we don't ICE in situations like rust-lang/rust#127299.
+
+trait Qux {
+    fn bar() -> i32;
+}
+
+pub struct Lint {
+    pub desc: &'static dyn Qux,
+    //~^ ERROR cannot be made into an object
+}
+
+static FOO: &Lint = &Lint { desc: "desc" };
+//~^ ERROR cannot be shared between threads safely
+//~| ERROR cannot be made into an object
+//~| ERROR cannot be made into an object
+
+fn main() {}
diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
new file mode 100644
index 00000000000..49e8d87f354
--- /dev/null
+++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
@@ -0,0 +1,87 @@
+error[E0038]: the trait `Qux` cannot be made into an object
+  --> $DIR/unsizing-wfcheck-issue-127299.rs:8:24
+   |
+LL |     pub desc: &'static dyn Qux,
+   |                        ^^^^^^^ `Qux` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
+   |
+LL | trait Qux {
+   |       --- this trait cannot be made into an object...
+LL |     fn bar() -> i32;
+   |        ^^^ ...because associated function `bar` has no `self` parameter
+help: consider turning `bar` into a method by giving it a `&self` argument
+   |
+LL |     fn bar(&self) -> i32;
+   |            +++++
+help: alternatively, consider constraining `bar` so it does not apply to trait objects
+   |
+LL |     fn bar() -> i32 where Self: Sized;
+   |                     +++++++++++++++++
+
+error[E0277]: `(dyn Qux + 'static)` cannot be shared between threads safely
+  --> $DIR/unsizing-wfcheck-issue-127299.rs:12:13
+   |
+LL | static FOO: &Lint = &Lint { desc: "desc" };
+   |             ^^^^^ `(dyn Qux + 'static)` cannot be shared between threads safely
+   |
+   = help: within `&'static Lint`, the trait `Sync` is not implemented for `(dyn Qux + 'static)`, which is required by `&'static Lint: Sync`
+   = note: required because it appears within the type `&'static (dyn Qux + 'static)`
+note: required because it appears within the type `Lint`
+  --> $DIR/unsizing-wfcheck-issue-127299.rs:7:12
+   |
+LL | pub struct Lint {
+   |            ^^^^
+   = note: required because it appears within the type `&'static Lint`
+   = note: shared static variables must have a type that implements `Sync`
+
+error[E0038]: the trait `Qux` cannot be made into an object
+  --> $DIR/unsizing-wfcheck-issue-127299.rs:12:35
+   |
+LL | static FOO: &Lint = &Lint { desc: "desc" };
+   |                                   ^^^^^^ `Qux` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
+   |
+LL | trait Qux {
+   |       --- this trait cannot be made into an object...
+LL |     fn bar() -> i32;
+   |        ^^^ ...because associated function `bar` has no `self` parameter
+   = note: required for the cast from `&'static str` to `&'static (dyn Qux + 'static)`
+help: consider turning `bar` into a method by giving it a `&self` argument
+   |
+LL |     fn bar(&self) -> i32;
+   |            +++++
+help: alternatively, consider constraining `bar` so it does not apply to trait objects
+   |
+LL |     fn bar() -> i32 where Self: Sized;
+   |                     +++++++++++++++++
+
+error[E0038]: the trait `Qux` cannot be made into an object
+  --> $DIR/unsizing-wfcheck-issue-127299.rs:12:35
+   |
+LL | static FOO: &Lint = &Lint { desc: "desc" };
+   |                                   ^^^^^^ `Qux` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
+   |
+LL | trait Qux {
+   |       --- this trait cannot be made into an object...
+LL |     fn bar() -> i32;
+   |        ^^^ ...because associated function `bar` has no `self` parameter
+help: consider turning `bar` into a method by giving it a `&self` argument
+   |
+LL |     fn bar(&self) -> i32;
+   |            +++++
+help: alternatively, consider constraining `bar` so it does not apply to trait objects
+   |
+LL |     fn bar() -> i32 where Self: Sized;
+   |                     +++++++++++++++++
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0038, E0277.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/structs-enums/newtype-struct-with-dtor.rs b/tests/ui/structs-enums/newtype-struct-with-dtor.rs
index 16439a7fedd..19672e41c9a 100644
--- a/tests/ui/structs-enums/newtype-struct-with-dtor.rs
+++ b/tests/ui/structs-enums/newtype-struct-with-dtor.rs
@@ -3,10 +3,8 @@
 #![allow(unused_variables)]
 //@ pretty-expanded FIXME #23616
 
-#[allow(dead_code)]
 pub struct Fd(u32);
 
-#[allow(dead_code)]
 fn foo(a: u32) {}
 
 impl Drop for Fd {
diff --git a/tests/ui/structs-enums/uninstantiable-struct.rs b/tests/ui/structs-enums/uninstantiable-struct.rs
index 1074dbcd6e6..97bc7d8414e 100644
--- a/tests/ui/structs-enums/uninstantiable-struct.rs
+++ b/tests/ui/structs-enums/uninstantiable-struct.rs
@@ -1,5 +1,4 @@
 //@ run-pass
-#[allow(dead_code)]
-pub struct Z(&'static Z);
+pub struct Z(#[allow(dead_code)] &'static Z);
 
 pub fn main() {}
diff --git a/tests/ui/structs/field-implied-unsizing-wfcheck.rs b/tests/ui/structs/field-implied-unsizing-wfcheck.rs
new file mode 100644
index 00000000000..a46c9b5a68b
--- /dev/null
+++ b/tests/ui/structs/field-implied-unsizing-wfcheck.rs
@@ -0,0 +1,32 @@
+struct FooStruct {
+    nested: &'static Bar<dyn std::fmt::Debug>,
+    //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+}
+
+struct FooTuple(&'static Bar<dyn std::fmt::Debug>);
+//~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+
+enum FooEnum1 {
+    Struct { nested: &'static Bar<dyn std::fmt::Debug> },
+    //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+}
+
+enum FooEnum2 {
+    Tuple(&'static Bar<dyn std::fmt::Debug>),
+    //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+}
+
+struct Bar<T>(T);
+
+fn main() {
+    // Ensure there's an error at the construction site, for error tainting purposes.
+
+    FooStruct { nested: &Bar(4) };
+    //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+    FooTuple(&Bar(4));
+    //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+    FooEnum1::Struct { nested: &Bar(4) };
+    //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+    FooEnum2::Tuple(&Bar(4));
+    //~^ ERROR the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+}
diff --git a/tests/ui/structs/field-implied-unsizing-wfcheck.stderr b/tests/ui/structs/field-implied-unsizing-wfcheck.stderr
new file mode 100644
index 00000000000..47d486ffa33
--- /dev/null
+++ b/tests/ui/structs/field-implied-unsizing-wfcheck.stderr
@@ -0,0 +1,163 @@
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/field-implied-unsizing-wfcheck.rs:2:13
+   |
+LL |     nested: &'static Bar<dyn std::fmt::Debug>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/field-implied-unsizing-wfcheck.rs:6:17
+   |
+LL | struct FooTuple(&'static Bar<dyn std::fmt::Debug>);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/field-implied-unsizing-wfcheck.rs:10:22
+   |
+LL |     Struct { nested: &'static Bar<dyn std::fmt::Debug> },
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/field-implied-unsizing-wfcheck.rs:15:11
+   |
+LL |     Tuple(&'static Bar<dyn std::fmt::Debug>),
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/field-implied-unsizing-wfcheck.rs:24:25
+   |
+LL |     FooStruct { nested: &Bar(4) };
+   |                         ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/field-implied-unsizing-wfcheck.rs:26:14
+   |
+LL |     FooTuple(&Bar(4));
+   |              ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/field-implied-unsizing-wfcheck.rs:28:32
+   |
+LL |     FooEnum1::Struct { nested: &Bar(4) };
+   |                                ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time
+  --> $DIR/field-implied-unsizing-wfcheck.rs:30:21
+   |
+LL |     FooEnum2::Tuple(&Bar(4));
+   |                     ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
+note: required by an implicit `Sized` bound in `Bar`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^ required by the implicit `Sized` requirement on this type parameter in `Bar`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/field-implied-unsizing-wfcheck.rs:19:12
+   |
+LL | struct Bar<T>(T);
+   |            ^  - ...if indirection were used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/suggestions/derive-clone-for-eq.fixed b/tests/ui/suggestions/derive-clone-for-eq.fixed
index cf800c6e47d..4dc362f9478 100644
--- a/tests/ui/suggestions/derive-clone-for-eq.fixed
+++ b/tests/ui/suggestions/derive-clone-for-eq.fixed
@@ -1,7 +1,6 @@
 //@ run-rustfix
 // https://github.com/rust-lang/rust/issues/79076
 
-#[allow(dead_code)]
 #[derive(Clone, Eq)] //~ ERROR [E0277]
 pub struct Struct<T: std::clone::Clone>(T);
 
diff --git a/tests/ui/suggestions/derive-clone-for-eq.rs b/tests/ui/suggestions/derive-clone-for-eq.rs
index 84736426bac..b3635000f16 100644
--- a/tests/ui/suggestions/derive-clone-for-eq.rs
+++ b/tests/ui/suggestions/derive-clone-for-eq.rs
@@ -1,7 +1,6 @@
 //@ run-rustfix
 // https://github.com/rust-lang/rust/issues/79076
 
-#[allow(dead_code)]
 #[derive(Clone, Eq)] //~ ERROR [E0277]
 pub struct Struct<T>(T);
 
diff --git a/tests/ui/suggestions/derive-clone-for-eq.stderr b/tests/ui/suggestions/derive-clone-for-eq.stderr
index 54670fbffcf..6fae6e1316d 100644
--- a/tests/ui/suggestions/derive-clone-for-eq.stderr
+++ b/tests/ui/suggestions/derive-clone-for-eq.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `T: Clone` is not satisfied
-  --> $DIR/derive-clone-for-eq.rs:5:17
+  --> $DIR/derive-clone-for-eq.rs:4:17
    |
 LL | #[derive(Clone, Eq)]
    |                 ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
    |
 note: required for `Struct<T>` to implement `PartialEq`
-  --> $DIR/derive-clone-for-eq.rs:8:19
+  --> $DIR/derive-clone-for-eq.rs:7:19
    |
 LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
    |         -----     ^^^^^^^^^^^^     ^^^^^^^^^
diff --git a/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr
index aeeec3aca34..3a1f685f16b 100644
--- a/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr
+++ b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr
@@ -2,18 +2,13 @@ error[E0700]: hidden type for `impl Iterator<Item = i32>` captures lifetime that
   --> $DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:7:5
    |
 LL |   fn bar(src: &crate::Foo) -> impl Iterator<Item = i32> {
-   |                ----------     ------------------------- opaque type defined here
-   |                |
-   |                hidden type `FilterMap<std::slice::Iter<'static, i32>, {closure@$DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:9:21: 9:24}>` captures the anonymous lifetime defined here
+   |                               ------------------------- opaque type defined here
 LL | /     [0].into_iter()
 LL | |
 LL | |         .filter_map(|_| foo(src))
    | |_________________________________^
    |
-help: to declare that `impl Iterator<Item = i32>` captures `'_`, you can introduce a named lifetime parameter `'a`
-   |
-LL | fn bar<'a>(src: &'a crate::Foo<'a>) -> impl Iterator<Item = i32> + 'a  {
-   |       ++++       ++           ++++                               ++++
+   = note: hidden type `FilterMap<std::slice::Iter<'static, i32>, {closure@$DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:9:21: 9:24}>` captures lifetime `'_`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
index a2a78ddc705..db16fff826f 100644
--- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
+++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
@@ -44,15 +44,13 @@ LL | #[derive(Debug, Copy, Clone)]
    |                       ----- in this derive macro expansion
 LL | pub struct AABB<K: Debug> {
 LL |     pub loc: Vector2<K>,
-   |     ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Clone`
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`
    |
-note: required for `Vector2<K>` to implement `Clone`
-  --> $DIR/missing-bound-in-derive-copy-impl-2.rs:4:23
+note: required by a bound in `Vector2`
+  --> $DIR/missing-bound-in-derive-copy-impl-2.rs:5:31
    |
-LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
-   |                               ---- unsatisfied trait bound introduced in this `derive` macro
+   |                               ^^^^ required by this bound in `Vector2`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting this bound
    |
diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
index 2ae0871b815..cf383b5c8ff 100644
--- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
+++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
@@ -95,15 +95,13 @@ LL | #[derive(Debug, Copy, Clone)]
    |                       ----- in this derive macro expansion
 LL | pub struct AABB<K> {
 LL |     pub loc: Vector2<K>,
-   |     ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Clone`
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`
    |
-note: required for `Vector2<K>` to implement `Clone`
-  --> $DIR/missing-bound-in-derive-copy-impl.rs:3:23
+note: required by a bound in `Vector2`
+  --> $DIR/missing-bound-in-derive-copy-impl.rs:4:31
    |
-LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^
 LL | pub struct Vector2<T: Debug + Copy + Clone> {
-   |                               ---- unsatisfied trait bound introduced in this `derive` macro
+   |                               ^^^^ required by this bound in `Vector2`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider restricting type parameter `K`
    |
diff --git a/tests/ui/suggestions/option-content-move.fixed b/tests/ui/suggestions/option-content-move.fixed
index ef07d55871e..4a5a9483c20 100644
--- a/tests/ui/suggestions/option-content-move.fixed
+++ b/tests/ui/suggestions/option-content-move.fixed
@@ -1,5 +1,4 @@
 //@ run-rustfix
-#[allow(dead_code)]
 pub struct LipogramCorpora {
     selections: Vec<(char, Option<String>)>,
 }
@@ -18,7 +17,6 @@ impl LipogramCorpora {
     }
 }
 
-#[allow(dead_code)]
 pub struct LipogramCorpora2 {
     selections: Vec<(char, Result<String, String>)>,
 }
diff --git a/tests/ui/suggestions/option-content-move.rs b/tests/ui/suggestions/option-content-move.rs
index 5be6358fd6a..90d05c74399 100644
--- a/tests/ui/suggestions/option-content-move.rs
+++ b/tests/ui/suggestions/option-content-move.rs
@@ -1,5 +1,4 @@
 //@ run-rustfix
-#[allow(dead_code)]
 pub struct LipogramCorpora {
     selections: Vec<(char, Option<String>)>,
 }
@@ -18,7 +17,6 @@ impl LipogramCorpora {
     }
 }
 
-#[allow(dead_code)]
 pub struct LipogramCorpora2 {
     selections: Vec<(char, Result<String, String>)>,
 }
diff --git a/tests/ui/suggestions/option-content-move.stderr b/tests/ui/suggestions/option-content-move.stderr
index b4ec5b180d2..a382a04344a 100644
--- a/tests/ui/suggestions/option-content-move.stderr
+++ b/tests/ui/suggestions/option-content-move.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `selection.1` which is behind a shared reference
-  --> $DIR/option-content-move.rs:11:20
+  --> $DIR/option-content-move.rs:10:20
    |
 LL |                 if selection.1.unwrap().contains(selection.0) {
    |                    ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
@@ -19,7 +19,7 @@ LL |                 if selection.1.clone().unwrap().contains(selection.0) {
    |                               ++++++++
 
 error[E0507]: cannot move out of `selection.1` which is behind a shared reference
-  --> $DIR/option-content-move.rs:30:20
+  --> $DIR/option-content-move.rs:28:20
    |
 LL |                 if selection.1.unwrap().contains(selection.0) {
    |                    ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
diff --git a/tests/ui/target-feature/asm-implied-features-issue-128125.rs b/tests/ui/target-feature/asm-implied-features-issue-128125.rs
new file mode 100644
index 00000000000..2b4f1d7df85
--- /dev/null
+++ b/tests/ui/target-feature/asm-implied-features-issue-128125.rs
@@ -0,0 +1,10 @@
+//@ only-x86_64
+//@ build-pass
+#![allow(dead_code)]
+
+#[target_feature(enable = "avx2")]
+unsafe fn demo(v: std::arch::x86_64::__m256i) {
+    std::arch::asm!("/* {v} */", v = in(ymm_reg) v);
+}
+
+fn main() {}
diff --git a/tests/ui/target-feature/implicit-features-cli.rs b/tests/ui/target-feature/implicit-features-cli.rs
new file mode 100644
index 00000000000..34e7c3d5066
--- /dev/null
+++ b/tests/ui/target-feature/implicit-features-cli.rs
@@ -0,0 +1,9 @@
+//@ only-wasm32-wasip1
+//@ compile-flags: -Ctarget-feature=+relaxed-simd --crate-type=lib
+//@ build-pass
+
+use std::arch::wasm32::*;
+
+pub fn test(a: v128, b: v128, m: v128) -> v128 {
+    i64x2_relaxed_laneselect(a, b, m)
+}
diff --git a/tests/ui/target-feature/implicit-features.rs b/tests/ui/target-feature/implicit-features.rs
new file mode 100644
index 00000000000..b9c48b0822d
--- /dev/null
+++ b/tests/ui/target-feature/implicit-features.rs
@@ -0,0 +1,10 @@
+//@ only-wasm32-wasip1
+//@ compile-flags: --crate-type=lib
+//@ build-pass
+
+use std::arch::wasm32::*;
+
+#[target_feature(enable = "relaxed-simd")]
+pub fn test(a: v128, b: v128, m: v128) -> v128 {
+    i64x2_relaxed_laneselect(a, b, m)
+}
diff --git a/tests/ui/target-feature/implied-features.rs b/tests/ui/target-feature/implied-features.rs
new file mode 100644
index 00000000000..4fdd843e6c2
--- /dev/null
+++ b/tests/ui/target-feature/implied-features.rs
@@ -0,0 +1,24 @@
+//@ only-x86_64
+//@ build-pass
+#![feature(target_feature_11)]
+#![allow(dead_code)]
+
+#[target_feature(enable = "ssse3")]
+fn call_ssse3() {}
+
+#[target_feature(enable = "avx")]
+fn call_avx() {}
+
+#[target_feature(enable = "avx2")]
+fn test_avx2() {
+    call_ssse3();
+    call_avx();
+}
+
+#[target_feature(enable = "fma")]
+fn test_fma() {
+    call_ssse3();
+    call_avx();
+}
+
+fn main() {}
diff --git a/tests/ui/target-feature/wasm-relaxed-simd.rs b/tests/ui/target-feature/wasm-relaxed-simd.rs
new file mode 100644
index 00000000000..34e7c3d5066
--- /dev/null
+++ b/tests/ui/target-feature/wasm-relaxed-simd.rs
@@ -0,0 +1,9 @@
+//@ only-wasm32-wasip1
+//@ compile-flags: -Ctarget-feature=+relaxed-simd --crate-type=lib
+//@ build-pass
+
+use std::arch::wasm32::*;
+
+pub fn test(a: v128, b: v128, m: v128) -> v128 {
+    i64x2_relaxed_laneselect(a, b, m)
+}
diff --git a/tests/ui/traits/object/generics.rs b/tests/ui/traits/object/generics.rs
index 0ae562c0d30..462b0bc5bb7 100644
--- a/tests/ui/traits/object/generics.rs
+++ b/tests/ui/traits/object/generics.rs
@@ -7,7 +7,6 @@ pub trait Trait2<A> {
     fn doit(&self) -> A;
 }
 
-#[allow(dead_code)]
 pub struct Impl<A1, A2, A3> {
     m1: marker::PhantomData<(A1,A2,A3)>,
     /*
diff --git a/tests/ui/try-trait/try-operator-custom.rs b/tests/ui/try-trait/try-operator-custom.rs
index ab0772dd228..936c0b0689a 100644
--- a/tests/ui/try-trait/try-operator-custom.rs
+++ b/tests/ui/try-trait/try-operator-custom.rs
@@ -31,7 +31,6 @@ impl<U, V> Try for MyResult<U, V> {
 impl<U, V, W> FromResidual<MyResult<Never, V>> for MyResult<U, W> where V: Into<W> {
     fn from_residual(x: MyResult<Never, V>) -> Self {
         match x {
-            MyResult::Awesome(u) => match u {},
             MyResult::Terrible(e) => MyResult::Terrible(e.into()),
         }
     }
@@ -42,7 +41,6 @@ type ResultResidual<E> = Result<std::convert::Infallible, E>;
 impl<U, V, W> FromResidual<ResultResidual<V>> for MyResult<U, W> where V: Into<W> {
     fn from_residual(x: ResultResidual<V>) -> Self {
         match x {
-            Ok(v) => match v {}
             Err(e) => MyResult::Terrible(e.into()),
         }
     }
@@ -51,7 +49,6 @@ impl<U, V, W> FromResidual<ResultResidual<V>> for MyResult<U, W> where V: Into<W
 impl<U, V, W> FromResidual<MyResult<Never, V>> for Result<U, W> where V: Into<W> {
     fn from_residual(x: MyResult<Never, V>) -> Self {
         match x {
-            MyResult::Awesome(u) => match u {},
             MyResult::Terrible(e) => Err(e.into()),
         }
     }
diff --git a/tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr b/tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
index dc0bea58a70..bf8829c0925 100644
--- a/tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
+++ b/tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
@@ -12,3 +12,13 @@ LL |     foo::<T, U>();
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0282`.
+Future incompatibility report: Future breakage diagnostic:
+warning: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:3:11
+   |
+LL | fn foo<T, U = u64>() -> (T, U) {
+   |           ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+
diff --git a/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.rs b/tests/ui/type/default_type_parameter_in_fn_or_impl.rs
index 33038e24bc6..33038e24bc6 100644
--- a/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.rs
+++ b/tests/ui/type/default_type_parameter_in_fn_or_impl.rs
diff --git a/tests/ui/type/default_type_parameter_in_fn_or_impl.stderr b/tests/ui/type/default_type_parameter_in_fn_or_impl.stderr
new file mode 100644
index 00000000000..a3205cd3c29
--- /dev/null
+++ b/tests/ui/type/default_type_parameter_in_fn_or_impl.stderr
@@ -0,0 +1,43 @@
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/default_type_parameter_in_fn_or_impl.rs:3:8
+   |
+LL | fn avg<T=i32>(_: T) {}
+   |        ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/default_type_parameter_in_fn_or_impl.rs:8:6
+   |
+LL | impl<T=i32> S<T> {}
+   |      ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+
+error: aborting due to 2 previous errors
+
+Future incompatibility report: Future breakage diagnostic:
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/default_type_parameter_in_fn_or_impl.rs:3:8
+   |
+LL | fn avg<T=i32>(_: T) {}
+   |        ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
+Future breakage diagnostic:
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/default_type_parameter_in_fn_or_impl.rs:8:6
+   |
+LL | impl<T=i32> S<T> {}
+   |      ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
index 6f74b89d224..03e91b52a2a 100644
--- a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
@@ -4,6 +4,7 @@ error[E0658]: use of unstable library feature 'core_pattern_type'
 LL | type NonNullU32 = pattern_type!(u32 is 1..);
    |                   ^^^^^^^^^^^^
    |
+   = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
    = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
@@ -13,6 +14,7 @@ error[E0658]: use of unstable library feature 'core_pattern_type'
 LL | type Percent = pattern_type!(u32 is 0..=100);
    |                ^^^^^^^^^^^^
    |
+   = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
    = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
@@ -22,6 +24,7 @@ error[E0658]: use of unstable library feature 'core_pattern_type'
 LL | type Negative = pattern_type!(i32 is ..=0);
    |                 ^^^^^^^^^^^^
    |
+   = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
    = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
@@ -31,6 +34,7 @@ error[E0658]: use of unstable library feature 'core_pattern_type'
 LL | type Positive = pattern_type!(i32 is 0..);
    |                 ^^^^^^^^^^^^
    |
+   = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
    = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
@@ -40,6 +44,7 @@ error[E0658]: use of unstable library feature 'core_pattern_type'
 LL | type Always = pattern_type!(Option<u32> is Some(_));
    |               ^^^^^^^^^^^^
    |
+   = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
    = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
diff --git a/tests/ui/typeck/issue-36708.stderr b/tests/ui/typeck/issue-36708.stderr
index 3589796b6aa..0aca575320f 100644
--- a/tests/ui/typeck/issue-36708.stderr
+++ b/tests/ui/typeck/issue-36708.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
+error[E0049]: associated function `foo` has 1 type parameter but its trait declaration has 0 type parameters
   --> $DIR/issue-36708.rs:8:12
    |
 LL |     fn foo<T>() {}
diff --git a/tests/ui/typeck/suggest-arg-comma-delete-ice.rs b/tests/ui/typeck/suggest-arg-comma-delete-ice.rs
new file mode 100644
index 00000000000..48d02e13eca
--- /dev/null
+++ b/tests/ui/typeck/suggest-arg-comma-delete-ice.rs
@@ -0,0 +1,19 @@
+//! Previously, we tried to remove extra arg commas when providing extra arg removal suggestions.
+//! One of the edge cases is having to account for an arg that has a closing delimiter `)`
+//! following it. However, the previous suggestion code assumed that the delimiter is in fact
+//! exactly the 1-byte `)` character. This assumption was proven incorrect, because we recover
+//! from Unicode-confusable delimiters in the parser, which means that the ending delimiter could be
+//! a multi-byte codepoint that looks *like* a `)`. Subtracing 1 byte could land us in the middle of
+//! a codepoint, triggering a codepoint boundary assertion.
+//!
+//! issue: rust-lang/rust#128717
+
+fn main() {
+    // The following example has been modified from #128717 to remove irrelevant Unicode as they do
+    // not otherwise partake in the right delimiter calculation causing the codepoint boundary
+    // assertion.
+    main(rahh);
+    //~^ ERROR unknown start of token
+    //~| ERROR this function takes 0 arguments but 1 argument was supplied
+    //~| ERROR cannot find value `rahh` in this scope
+}
diff --git a/tests/ui/typeck/suggest-arg-comma-delete-ice.stderr b/tests/ui/typeck/suggest-arg-comma-delete-ice.stderr
new file mode 100644
index 00000000000..53608391f3c
--- /dev/null
+++ b/tests/ui/typeck/suggest-arg-comma-delete-ice.stderr
@@ -0,0 +1,38 @@
+error: unknown start of token: \u{ff09}
+  --> $DIR/suggest-arg-comma-delete-ice.rs:15:14
+   |
+LL |     main(rahh);
+   |              ^^
+   |
+help: Unicode character ')' (Fullwidth Right Parenthesis) looks like ')' (Right Parenthesis), but it is not
+   |
+LL |     main(rahh);
+   |              ~
+
+error[E0425]: cannot find value `rahh` in this scope
+  --> $DIR/suggest-arg-comma-delete-ice.rs:15:10
+   |
+LL |     main(rahh);
+   |          ^^^^ not found in this scope
+
+error[E0061]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/suggest-arg-comma-delete-ice.rs:15:5
+   |
+LL |     main(rahh);
+   |     ^^^^ ---- unexpected argument
+   |
+note: function defined here
+  --> $DIR/suggest-arg-comma-delete-ice.rs:11:4
+   |
+LL | fn main() {
+   |    ^^^^
+help: remove the extra argument
+   |
+LL -     main(rahh);
+LL +     main();
+   |
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0061, E0425.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs b/tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs
index 3130fb3fe9e..722d9b4ed29 100644
--- a/tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs
+++ b/tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs
@@ -1,7 +1,5 @@
 //@ check-pass
 
-#![feature(min_exhaustive_patterns)]
-
 enum Void {}
 fn main() {
     let a: Option<Void> = None;
diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr b/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr
index bc1a9fa4191..50f33607c06 100644
--- a/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr
+++ b/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0005]: refutable pattern in local binding
-  --> $DIR/uninhabited-irrefutable.rs:31:9
+  --> $DIR/uninhabited-irrefutable.rs:30:9
    |
 LL |     let Foo::D(_y, _z) = x;
    |         ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
@@ -7,7 +7,7 @@ LL |     let Foo::D(_y, _z) = x;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `Foo` defined here
-  --> $DIR/uninhabited-irrefutable.rs:20:6
+  --> $DIR/uninhabited-irrefutable.rs:19:6
    |
 LL | enum Foo {
    |      ^^^
diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr b/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr
new file mode 100644
index 00000000000..50f33607c06
--- /dev/null
+++ b/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr
@@ -0,0 +1,26 @@
+error[E0005]: refutable pattern in local binding
+  --> $DIR/uninhabited-irrefutable.rs:30:9
+   |
+LL |     let Foo::D(_y, _z) = x;
+   |         ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Foo` defined here
+  --> $DIR/uninhabited-irrefutable.rs:19:6
+   |
+LL | enum Foo {
+   |      ^^^
+LL |
+LL |     A(foo::SecretlyEmpty),
+   |     - not covered
+   = note: pattern `Foo::A(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
+   = note: the matched value is of type `Foo`
+help: you might want to use `let else` to handle the variant that isn't matched
+   |
+LL |     let Foo::D(_y, _z) = x else { todo!() };
+   |                            ++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.rs b/tests/ui/uninhabited/uninhabited-irrefutable.rs
index c1f4e5f8e27..cbaa9896003 100644
--- a/tests/ui/uninhabited/uninhabited-irrefutable.rs
+++ b/tests/ui/uninhabited/uninhabited-irrefutable.rs
@@ -1,6 +1,5 @@
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 
 mod foo {
diff --git a/tests/ui/uninhabited/uninhabited-matches-feature-gated.rs b/tests/ui/uninhabited/uninhabited-matches-feature-gated.rs
index e804afcf9ed..1b158dd48e9 100644
--- a/tests/ui/uninhabited/uninhabited-matches-feature-gated.rs
+++ b/tests/ui/uninhabited/uninhabited-matches-feature-gated.rs
@@ -15,10 +15,10 @@ fn main() {
     let _ = match x {}; //~ ERROR non-exhaustive
 
     let x: (Void,) = unsafe { zeroed() };
-    let _ = match x {}; //~ ERROR non-exhaustive
+    let _ = match x {};
 
     let x: [Void; 1] = unsafe { zeroed() };
-    let _ = match x {}; //~ ERROR non-exhaustive
+    let _ = match x {};
 
     let x: &[Void] = unsafe { zeroed() };
     let _ = match x {   //~ ERROR non-exhaustive
@@ -29,11 +29,10 @@ fn main() {
     let _ = match x {}; // okay
 
     let x: Result<u32, Void> = Ok(23);
-    let _ = match x {   //~ ERROR non-exhaustive
+    let _ = match x {
         Ok(x) => x,
     };
 
     let x: Result<u32, Void> = Ok(23);
     let Ok(x) = x;
-    //~^ ERROR refutable
 }
diff --git a/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
index 466d7f2eadb..2cd3c9375d0 100644
--- a/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
+++ b/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
@@ -36,34 +36,6 @@ LL +         _ => todo!(),
 LL ~     };
    |
 
-error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
-  --> $DIR/uninhabited-matches-feature-gated.rs:18:19
-   |
-LL |     let _ = match x {};
-   |                   ^
-   |
-   = note: the matched value is of type `(Void,)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     let _ = match x {
-LL +         _ => todo!(),
-LL ~     };
-   |
-
-error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
-  --> $DIR/uninhabited-matches-feature-gated.rs:21:19
-   |
-LL |     let _ = match x {};
-   |                   ^
-   |
-   = note: the matched value is of type `[Void; 1]`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     let _ = match x {
-LL +         _ => todo!(),
-LL ~     };
-   |
-
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:24:19
    |
@@ -71,45 +43,13 @@ LL |     let _ = match x {
    |                   ^ pattern `&[_, ..]` not covered
    |
    = note: the matched value is of type `&[Void]`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &[] => (),
 LL ~         &[_, ..] => todo!(),
    |
 
-error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/uninhabited-matches-feature-gated.rs:32:19
-   |
-LL |     let _ = match x {
-   |                   ^ pattern `Err(_)` not covered
-   |
-note: `Result<u32, Void>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
-   = note: the matched value is of type `Result<u32, Void>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
-   |
-LL ~         Ok(x) => x,
-LL ~         Err(_) => todo!(),
-   |
-
-error[E0005]: refutable pattern in local binding
-  --> $DIR/uninhabited-matches-feature-gated.rs:37:9
-   |
-LL |     let Ok(x) = x;
-   |         ^^^^^ pattern `Err(_)` not covered
-   |
-   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `Result<u32, Void>`
-help: you might want to use `let else` to handle the variant that isn't matched
-   |
-LL |     let Ok(x) = x else { todo!() };
-   |                   ++++++++++++++++
-
-error: aborting due to 7 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0004, E0005.
-For more information about an error, try `rustc --explain E0004`.
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/uninhabited/uninhabited-patterns.rs b/tests/ui/uninhabited/uninhabited-patterns.rs
index ae12c0fc4af..988383e691b 100644
--- a/tests/ui/uninhabited/uninhabited-patterns.rs
+++ b/tests/ui/uninhabited/uninhabited-patterns.rs
@@ -1,6 +1,5 @@
 #![feature(box_patterns)]
 #![feature(never_type)]
-#![feature(min_exhaustive_patterns)]
 #![deny(unreachable_patterns)]
 
 mod foo {
diff --git a/tests/ui/uninhabited/uninhabited-patterns.stderr b/tests/ui/uninhabited/uninhabited-patterns.stderr
index ca62386d7ef..4e4aaa93f80 100644
--- a/tests/ui/uninhabited/uninhabited-patterns.stderr
+++ b/tests/ui/uninhabited/uninhabited-patterns.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:30:9
+  --> $DIR/uninhabited-patterns.rs:29:9
    |
 LL |         Ok(box _) => (),
    |         ^^^^^^^^^
    |
    = note: this pattern matches no values because `NotSoSecretlyEmpty` is uninhabited
 note: the lint level is defined here
-  --> $DIR/uninhabited-patterns.rs:4:9
+  --> $DIR/uninhabited-patterns.rs:3:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:39:9
+  --> $DIR/uninhabited-patterns.rs:38:9
    |
 LL |         Err(Ok(_y)) => (),
    |         ^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |         Err(Ok(_y)) => (),
    = note: this pattern matches no values because `NotSoSecretlyEmpty` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:42:15
+  --> $DIR/uninhabited-patterns.rs:41:15
    |
 LL |     while let Some(_y) = foo() {
    |               ^^^^^^^^
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
index 92c2e7b4884..29472df897a 100644
--- a/tests/ui/unpretty/expanded-exhaustive.rs
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -25,7 +25,6 @@
 #![feature(trait_alias)]
 #![feature(try_blocks)]
 #![feature(unnamed_fields)]
-#![feature(unsafe_extern_blocks)]
 #![feature(yeet_expr)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
index 137a8aa5510..cf2f6f8cbaa 100644
--- a/tests/ui/unpretty/expanded-exhaustive.stdout
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -26,7 +26,6 @@
 #![feature(trait_alias)]
 #![feature(try_blocks)]
 #![feature(unnamed_fields)]
-#![feature(unsafe_extern_blocks)]
 #![feature(yeet_expr)]
 #![allow(incomplete_features)]
 #[prelude_import]
diff --git a/tests/ui/wf/wf-in-where-clause-static.current.stderr b/tests/ui/wf/wf-in-where-clause-static.current.stderr
new file mode 100644
index 00000000000..d0bb89884c6
--- /dev/null
+++ b/tests/ui/wf/wf-in-where-clause-static.current.stderr
@@ -0,0 +1,12 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/wf-in-where-clause-static.rs:18:18
+   |
+LL |     let s = foo(&String::from("blah blah blah"));
+   |             -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
+   |             |    |
+   |             |    creates a temporary value which is freed while still in use
+   |             argument requires that borrow lasts for `'static`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/wf/wf-in-where-clause-static.next.stderr b/tests/ui/wf/wf-in-where-clause-static.next.stderr
new file mode 100644
index 00000000000..d0bb89884c6
--- /dev/null
+++ b/tests/ui/wf/wf-in-where-clause-static.next.stderr
@@ -0,0 +1,12 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/wf-in-where-clause-static.rs:18:18
+   |
+LL |     let s = foo(&String::from("blah blah blah"));
+   |             -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
+   |             |    |
+   |             |    creates a temporary value which is freed while still in use
+   |             argument requires that borrow lasts for `'static`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/wf/wf-in-where-clause-static.rs b/tests/ui/wf/wf-in-where-clause-static.rs
index a3d360e1fb5..8ee654ef7cf 100644
--- a/tests/ui/wf/wf-in-where-clause-static.rs
+++ b/tests/ui/wf/wf-in-where-clause-static.rs
@@ -1,9 +1,6 @@
-//@ check-pass
-//@ known-bug: #98117
-
-// Should fail. Functions are responsible for checking the well-formedness of
-// their own where clauses, so this should fail and require an explicit bound
-// `T: 'static`.
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 use std::fmt::Display;
 
@@ -19,5 +16,6 @@ where
 
 fn main() {
     let s = foo(&String::from("blah blah blah"));
+    //~^ ERROR temporary value dropped while borrowed
     println!("{}", s);
 }
diff --git a/triagebot.toml b/triagebot.toml
index 2795f937284..33108f743cb 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -778,6 +778,14 @@ If this was unintentional then you should revert the changes before this PR is m
 Otherwise, you can ignore this comment.
 """
 
+[mentions."library/Cargo.lock"]
+message = """
+These commits modify the `library/Cargo.lock` file. Unintentional changes to `library/Cargo.lock` can be introduced when switching branches and rebasing PRs.
+
+If this was unintentional then you should revert the changes before this PR is merged.
+Otherwise, you can ignore this comment.
+"""
+
 [mentions."src/tools/x"]
 message = "`src/tools/x` was changed. Bump version of Cargo.toml in `src/tools/x` so tidy will suggest installing the new version."