about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurențiu Nicola <lnicola@dend.ro>2024-07-16 16:23:47 +0300
committerLaurențiu Nicola <lnicola@dend.ro>2024-07-16 16:23:47 +0300
commit137c736d667dd500ddac47450df21ae9be345ba0 (patch)
tree09b90094b7563b94884e3c90565d7bbd7b5eee5c
parent2e37675cc91052ea5a3fe56019e2d66e5822f1a5 (diff)
parent72e22554caa473df6af10f0ab6c3c7c7c5ef8841 (diff)
downloadrust-137c736d667dd500ddac47450df21ae9be345ba0.tar.gz
rust-137c736d667dd500ddac47450df21ae9be345ba0.zip
Merge from rust-lang/rust
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--Cargo.lock8
-rw-r--r--INSTALL.md2
-rw-r--r--RELEASES.md158
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs23
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs136
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs6
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs154
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock94
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh4
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs36
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/object.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs20
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs1
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs33
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs14
-rw-r--r--compiler/rustc_data_structures/Cargo.toml1
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs9
-rw-r--r--compiler/rustc_data_structures/src/hashes.rs17
-rw-r--r--compiler/rustc_data_structures/src/lib.rs2
-rw-r--r--compiler/rustc_data_structures/src/sip128.rs505
-rw-r--r--compiler/rustc_data_structures/src/sip128/tests.rs304
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs162
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher/tests.rs65
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs6
-rw-r--r--compiler/rustc_expand/src/config.rs30
-rw-r--r--compiler/rustc_feature/src/accepted.rs4
-rw-r--r--compiler/rustc_feature/src/lib.rs4
-rw-r--r--compiler/rustc_feature/src/removed.rs9
-rw-r--r--compiler/rustc_feature/src/unstable.rs12
-rw-r--r--compiler/rustc_hir/src/hir.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs104
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs120
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs1
-rw-r--r--compiler/rustc_infer/messages.ftl4
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs29
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/region.rs121
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/messages.ftl19
-rw-r--r--compiler/rustc_lint/src/builtin.rs137
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/lints.rs32
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs27
-rw-r--r--compiler/rustc_llvm/build.rs3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp17
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs4
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs9
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs4
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs13
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs17
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs6
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs4
-rw-r--r--compiler/rustc_middle/src/traits/solve/cache.rs121
-rw-r--r--compiler/rustc_middle/src/ty/context.rs34
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs4
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs254
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs366
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs242
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs30
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/initialized.rs18
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs12
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs338
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mappings.rs22
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs17
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs20
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs14
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/inspect/build.rs69
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/search_graph.rs623
-rw-r--r--compiler/rustc_parse/messages.ftl10
-rw-r--r--compiler/rustc_parse/src/errors.rs409
-rw-r--r--compiler/rustc_parse/src/lib.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs122
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs51
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs11
-rw-r--r--compiler/rustc_parse/src/parser/item.rs12
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs76
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs50
-rw-r--r--compiler/rustc_parse/src/parser/path.rs2
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs8
-rw-r--r--compiler/rustc_parse/src/parser/tests.rs359
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs23
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/errors.rs8
-rw-r--r--compiler/rustc_passes/src/stability.rs6
-rw-r--r--compiler/rustc_query_system/src/cache.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs23
-rw-r--r--compiler/rustc_resolve/src/errors.rs14
-rw-r--r--compiler/rustc_resolve/src/ident.rs44
-rw-r--r--compiler/rustc_resolve/src/lib.rs11
-rw-r--r--compiler/rustc_session/src/config.rs2
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs1
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs14
-rw-r--r--compiler/rustc_target/src/spec/abi/mod.rs26
-rw-r--r--compiler/rustc_target/src/spec/mod.rs17
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i386_apple_ios.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_linux_android.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/msp430_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs12
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/target_features.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs19
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs46
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs29
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs37
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs30
-rw-r--r--compiler/rustc_type_ir/src/interner.rs48
-rw-r--r--compiler/rustc_type_ir/src/lib.rs1
-rw-r--r--compiler/rustc_type_ir/src/search_graph/global_cache.rs118
-rw-r--r--compiler/rustc_type_ir/src/search_graph/mod.rs605
-rw-r--r--compiler/rustc_type_ir/src/search_graph/validate.rs75
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs (renamed from compiler/rustc_type_ir/src/solve.rs)0
-rw-r--r--compiler/stable_mir/src/ty.rs1
-rw-r--r--config.example.toml10
-rw-r--r--library/alloc/src/boxed.rs6
-rw-r--r--library/alloc/src/rc.rs34
-rw-r--r--library/alloc/src/string.rs3
-rw-r--r--library/alloc/src/sync.rs34
-rw-r--r--library/alloc/src/vec/into_iter.rs7
-rw-r--r--library/alloc/src/vec/mod.rs6
-rw-r--r--library/core/src/borrow.rs1
-rw-r--r--library/core/src/cell/lazy.rs4
-rw-r--r--library/core/src/char/methods.rs5
-rw-r--r--library/core/src/char/mod.rs2
-rw-r--r--library/core/src/ffi/c_str.rs13
-rw-r--r--library/core/src/iter/sources/repeat.rs4
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/mem/manually_drop.rs3
-rw-r--r--library/core/src/mem/maybe_uninit.rs15
-rw-r--r--library/core/src/num/f128.rs247
-rw-r--r--library/core/src/num/f16.rs298
-rw-r--r--library/core/src/ptr/const_ptr.rs12
-rw-r--r--library/core/src/ptr/mut_ptr.rs12
-rw-r--r--library/core/src/ptr/non_null.rs15
-rw-r--r--library/core/src/slice/iter.rs60
-rw-r--r--library/core/src/slice/mod.rs26
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--library/std/src/collections/hash/map.rs2
-rw-r--r--library/std/src/env.rs14
-rw-r--r--library/std/src/f128/tests.rs66
-rw-r--r--library/std/src/f16/tests.rs66
-rw-r--r--library/std/src/f64.rs6
-rw-r--r--library/std/src/ffi/os_str.rs4
-rw-r--r--library/std/src/fs/tests.rs23
-rw-r--r--library/std/src/io/buffered/bufwriter.rs22
-rw-r--r--library/std/src/io/buffered/tests.rs10
-rw-r--r--library/std/src/io/cursor.rs2
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs7
-rw-r--r--library/std/src/io/mod.rs20
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/os/darwin/fs.rs (renamed from library/std/src/os/macos/fs.rs)6
-rw-r--r--library/std/src/os/darwin/mod.rs20
-rw-r--r--library/std/src/os/darwin/raw.rs (renamed from library/std/src/os/ios/raw.rs)14
-rw-r--r--library/std/src/os/ios/fs.rs160
-rw-r--r--library/std/src/os/ios/mod.rs28
-rw-r--r--library/std/src/os/macos/mod.rs28
-rw-r--r--library/std/src/os/macos/raw.rs83
-rw-r--r--library/std/src/os/mod.rs12
-rw-r--r--library/std/src/os/unix/mod.rs12
-rw-r--r--library/std/src/os/visionos/fs.rs160
-rw-r--r--library/std/src/os/visionos/mod.rs6
-rw-r--r--library/std/src/os/visionos/raw.rs83
-rw-r--r--library/std/src/os/watchos/fs.rs160
-rw-r--r--library/std/src/os/watchos/mod.rs6
-rw-r--r--library/std/src/os/watchos/raw.rs83
-rw-r--r--library/std/src/os/windows/io/raw.rs28
-rw-r--r--library/std/src/os/windows/io/socket.rs8
-rw-r--r--library/std/src/os/windows/mod.rs1
-rw-r--r--library/std/src/os/windows/process.rs4
-rw-r--r--library/std/src/panicking.rs8
-rw-r--r--library/std/src/process.rs4
-rw-r--r--library/std/src/process/tests.rs24
-rw-r--r--library/std/src/rt.rs14
-rw-r--r--library/std/src/sync/condvar.rs3
-rw-r--r--library/std/src/sync/lazy_lock.rs4
-rw-r--r--library/std/src/sync/mpmc/array.rs22
-rw-r--r--library/std/src/sync/mpmc/counter.rs4
-rw-r--r--library/std/src/sync/mpmc/list.rs38
-rw-r--r--library/std/src/sync/mpmc/zero.rs20
-rw-r--r--library/std/src/sync/once_lock.rs4
-rw-r--r--library/std/src/sync/reentrant_lock.rs4
-rw-r--r--library/std/src/sync/rwlock.rs2
-rw-r--r--library/std/src/sys/backtrace.rs53
-rw-r--r--library/std/src/sys/exit_guard.rs72
-rw-r--r--library/std/src/sys/mod.rs3
-rw-r--r--library/std/src/sys/pal/mod.rs31
-rw-r--r--library/std/src/sys/pal/unix/fs.rs60
-rw-r--r--library/std/src/sys/pal/unix/linux/pidfd/tests.rs16
-rw-r--r--library/std/src/sys/pal/unix/mod.rs4
-rw-r--r--library/std/src/sys/pal/unix/os.rs1
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix.rs117
-rw-r--r--library/std/src/sys/pal/windows/alloc.rs147
-rw-r--r--library/std/src/sys/pal/windows/api.rs6
-rw-r--r--library/std/src/sys/pal/windows/c.rs81
-rw-r--r--library/std/src/sys/pal/windows/c/windows_targets.rs13
-rw-r--r--library/std/src/sys/pal/windows/compat.rs6
-rw-r--r--library/std/src/sys/pal/windows/fs.rs74
-rw-r--r--library/std/src/sys/pal/windows/handle.rs14
-rw-r--r--library/std/src/sys/pal/windows/io.rs13
-rw-r--r--library/std/src/sys/pal/windows/mod.rs25
-rw-r--r--library/std/src/sys/pal/windows/net.rs10
-rw-r--r--library/std/src/sys/pal/windows/os.rs11
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs19
-rw-r--r--library/std/src/sys/pal/windows/process.rs28
-rw-r--r--library/std/src/sys/pal/windows/rand.rs2
-rw-r--r--library/std/src/sys/pal/windows/stack_overflow.rs3
-rw-r--r--library/std/src/sys/pal/windows/stdio.rs34
-rw-r--r--library/std/src/sys/pal/windows/thread.rs3
-rw-r--r--library/std/src/sys/pal/windows/time.rs14
-rw-r--r--library/std/src/sys/sync/mutex/windows7.rs2
-rw-r--r--library/std/src/sys/sync/thread_parking/windows.rs9
-rw-r--r--library/std/src/sys/thread_local/guard/windows.rs5
-rw-r--r--library/std/src/sys/thread_local/key/windows.rs4
-rw-r--r--library/std/src/sys_common/wtf8.rs14
-rw-r--r--library/sysroot/Cargo.toml1
-rw-r--r--rustfmt.toml2
-rw-r--r--src/bootstrap/Cargo.lock1
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/README.md18
-rw-r--r--src/bootstrap/bootstrap.py2
-rw-r--r--src/bootstrap/mk/Makefile.in9
-rw-r--r--src/bootstrap/src/bin/main.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs46
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs12
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs15
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs7
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs60
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs89
-rw-r--r--src/bootstrap/src/core/build_steps/toolstate.rs95
-rw-r--r--src/bootstrap/src/core/builder.rs14
-rw-r--r--src/bootstrap/src/core/builder/tests.rs2
-rw-r--r--src/bootstrap/src/core/config/config.rs169
-rw-r--r--src/bootstrap/src/core/config/flags.rs2
-rw-r--r--src/bootstrap/src/core/download.rs8
-rw-r--r--src/bootstrap/src/core/sanity.rs4
-rw-r--r--src/bootstrap/src/lib.rs114
-rw-r--r--src/bootstrap/src/utils/channel.rs11
-rw-r--r--src/bootstrap/src/utils/exec.rs59
-rw-r--r--src/bootstrap/src/utils/helpers.rs11
-rw-r--r--src/bootstrap/src/utils/render_tests.rs3
-rw-r--r--src/bootstrap/src/utils/tarball.rs14
-rw-r--r--src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch37
-rw-r--r--src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch117
-rw-r--r--src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch58
-rw-r--r--src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig4
-rwxr-xr-xsrc/ci/scripts/install-clang.sh2
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/embedded-book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/platform-support.md6
-rw-r--r--src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md2
-rw-r--r--src/librustdoc/clean/mod.rs9
-rw-r--r--src/librustdoc/clean/simplify.rs2
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/html/format.rs14
-rw-r--r--src/librustdoc/html/render/search_index.rs6
-rw-r--r--src/librustdoc/json/conversions.rs1
-rw-r--r--src/rustdoc-json-types/lib.rs4
-rw-r--r--src/tools/build_helper/src/ci.rs14
-rw-r--r--src/tools/build_helper/src/drop_bomb/mod.rs (renamed from src/tools/run-make-support/src/drop_bomb/mod.rs)20
-rw-r--r--src/tools/build_helper/src/drop_bomb/tests.rs (renamed from src/tools/run-make-support/src/drop_bomb/tests.rs)0
-rw-r--r--src/tools/build_helper/src/lib.rs1
-rw-r--r--src/tools/clippy/.github/workflows/lintcheck.yml4
-rw-r--r--src/tools/clippy/CHANGELOG.md6
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md3
-rw-r--r--src/tools/clippy/clippy.toml4
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs3
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs4
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_range.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs496
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs134
-rw-r--r--src/tools/clippy/clippy_lints/src/byte_char_slices.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cfg_not_test.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/incompatible_msrv.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/init_numbered_fields.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rotate.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs111
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs (renamed from src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs)14
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs140
-rw-r--r--src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/types/type_complexity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs67
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs26
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml1
-rw-r--r--src/tools/clippy/lintcheck/README.md16
-rw-r--r--src/tools/clippy/lintcheck/lintcheck_crates.toml52
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs4
-rw-r--r--src/tools/clippy/lintcheck/src/driver.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/input.rs288
-rw-r--r--src/tools/clippy/lintcheck/src/json.rs99
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs595
-rw-r--r--src/tools/clippy/lintcheck/src/output.rs235
-rw-r--r--src/tools/clippy/lintcheck/src/popular_crates.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/recursive.rs7
-rw-r--r--src/tools/clippy/rust-toolchain3
-rw-r--r--src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr16
-rw-r--r--src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed10
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs10
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr12
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr36
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.rs11
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.stderr18
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.rs26
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.stderr78
-rw-r--r--src/tools/clippy/tests/ui/await_holding_refcell_ref.rs12
-rw-r--r--src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr24
-rw-r--r--src/tools/clippy/tests/ui/byte_char_slices.fixed13
-rw-r--r--src/tools/clippy/tests/ui/byte_char_slices.rs13
-rw-r--r--src/tools/clippy/tests/ui/byte_char_slices.stderr38
-rw-r--r--src/tools/clippy/tests/ui/cfg_not_test.rs32
-rw-r--r--src/tools/clippy/tests/ui/cfg_not_test.stderr45
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12616.stderr2
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.rs1
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed47
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs43
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr56
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed12
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs12
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr12
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed31
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.rs22
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr49
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs17
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr18
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.fixed36
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.rs36
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.stderr8
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.rs6
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.stderr21
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.rs8
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.stderr29
-rw-r--r--src/tools/clippy/tests/ui/init_numbered_fields.fixed (renamed from src/tools/clippy/tests/ui/numbered_fields.fixed)9
-rw-r--r--src/tools/clippy/tests/ui/init_numbered_fields.rs (renamed from src/tools/clippy/tests/ui/numbered_fields.rs)9
-rw-r--r--src/tools/clippy/tests/ui/init_numbered_fields.stderr (renamed from src/tools/clippy/tests/ui/numbered_fields.stderr)12
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.rs39
-rw-r--r--src/tools/clippy/tests/ui/iter_next_loop.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_next_loop.stderr10
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.stderr24
-rw-r--r--src/tools/clippy/tests/ui/manual_rotate.fixed31
-rw-r--r--src/tools/clippy/tests/ui/manual_rotate.rs31
-rw-r--r--src/tools/clippy/tests/ui/manual_rotate.stderr71
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs18
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed30
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs30
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr41
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed14
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs14
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr59
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed (renamed from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed)2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_thread_local.rs (renamed from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs)2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr (renamed from src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr)16
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs18
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr52
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed4
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs4
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr15
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed35
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs35
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr28
-rw-r--r--src/tools/clippy/tests/ui/overflow_check_conditional.rs36
-rw-r--r--src/tools/clippy/tests/ui/overflow_check_conditional.stderr53
-rw-r--r--src/tools/clippy/tests/ui/panicking_overflow_checks.rs27
-rw-r--r--src/tools/clippy/tests/ui/panicking_overflow_checks.stderr41
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.stderr66
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed4
-rw-r--r--src/tools/clippy/tests/ui/rename.rs4
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr130
-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.stderr61
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs26
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr29
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.fixed14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.rs14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_operation.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed19
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs19
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.stderr60
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.rs3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.rs3
-rw-r--r--src/tools/compiletest/src/header.rs18
-rw-r--r--src/tools/jsondoclint/src/validator.rs1
-rw-r--r--src/tools/lint-docs/src/groups.rs2
-rw-r--r--src/tools/lint-docs/src/lib.rs2
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs26
-rwxr-xr-xsrc/tools/miri/ci/ci.sh4
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs3
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs12
-rw-r--r--src/tools/miri/src/concurrency/cpu_affinity.rs90
-rw-r--r--src/tools/miri/src/concurrency/mod.rs1
-rw-r--r--src/tools/miri/src/concurrency/sync.rs21
-rw-r--r--src/tools/miri/src/concurrency/thread.rs5
-rw-r--r--src/tools/miri/src/eval.rs3
-rw-r--r--src/tools/miri/src/helpers.rs55
-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.rs23
-rw-r--r--src/tools/miri/src/provenance_gc.rs11
-rw-r--r--src/tools/miri/src/shims/tls.rs65
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs7
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs95
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs13
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs24
-rw-r--r--src/tools/miri/src/shims/unix/macos/mod.rs1
-rw-r--r--src/tools/miri/src/shims/unix/macos/sync.rs107
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs2
-rwxr-xr-xsrc/tools/miri/test-cargo-miri/run-test.py20
-rw-r--r--src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref22
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs13
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr13
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs12
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr13
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs13
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr13
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs12
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr13
-rw-r--r--src/tools/miri/tests/fail-dep/libc/affinity.rs17
-rw-r--r--src/tools/miri/tests/fail-dep/libc/affinity.stderr20
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs27
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr15
-rw-r--r--src/tools/miri/tests/fail/alloc/global_system_mixup.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs20
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr20
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs25
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-affinity.rs218
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs.rs35
-rw-r--r--src/tools/miri/tests/pass/float.rs642
-rw-r--r--src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs43
-rw-r--r--src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout7
-rw-r--r--src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs3
-rw-r--r--src/tools/run-make-support/Cargo.toml2
-rw-r--r--src/tools/run-make-support/src/command.rs2
-rw-r--r--src/tools/run-make-support/src/diff/mod.rs2
-rw-r--r--src/tools/run-make-support/src/lib.rs6
-rw-r--r--src/tools/run-make-support/src/rustc.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs2
-rw-r--r--src/tools/rust-installer/src/combiner.rs2
-rwxr-xr-xsrc/tools/rust-installer/test.sh2
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt5
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--tests/assembly/x86-return-float.rs328
-rw-r--r--tests/codegen/float/f128.rs11
-rw-r--r--tests/codegen/float/f16.rs11
-rw-r--r--tests/codegen/issues/issue-32031.rs10
-rw-r--r--tests/codegen/union-abi.rs10
-rw-r--r--tests/coverage/closure.cov-map16
-rw-r--r--tests/coverage/try_error_result.cov-map199
-rw-r--r--tests/crashes/126416.rs20
-rw-r--r--tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir8
-rw-r--r--tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir8
-rw-r--r--tests/mir-opt/building/match/match_false_edges.main.built.after.mir86
-rw-r--r--tests/mir-opt/building/match/simple_match.match_bool.built.after.mir20
-rw-r--r--tests/mir-opt/building/match/simple_match.match_enum.built.after.mir26
-rw-r--r--tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir28
-rw-r--r--tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir34
-rw-r--r--tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir34
-rw-r--r--tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff8
-rw-r--r--tests/mir-opt/const_debuginfo.rs2
-rw-r--r--tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff6
-rw-r--r--tests/mir-opt/const_prop/address_of_pair.rs1
-rw-r--r--tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/checked_add.rs2
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate.rs1
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs1
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs1
-rw-r--r--tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir4
-rw-r--r--tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir4
-rw-r--r--tests/mir-opt/const_prop/return_place.rs2
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/slice_len.rs2
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff6
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff6
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.rs1
-rw-r--r--tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff65
-rw-r--r--tests/mir-opt/dataflow-const-prop/aggregate_copy.rs42
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff10
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff10
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.rs2
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff12
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff12
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff12
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff12
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff14
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff14
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff14
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff14
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs2
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.rs1
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff23
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff23
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff67
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff67
-rw-r--r--tests/mir-opt/dataflow-const-prop/struct.rs7
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff14
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff14
-rw-r--r--tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff18
-rw-r--r--tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff18
-rw-r--r--tests/mir-opt/dataflow-const-prop/tuple.rs1
-rw-r--r--tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff48
-rw-r--r--tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff48
-rw-r--r--tests/mir-opt/dest-prop/branch.rs5
-rw-r--r--tests/mir-opt/dest-prop/copy_propagation_arg.rs18
-rw-r--r--tests/mir-opt/dest-prop/cycle.rs5
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_79191.rs8
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_better.rs8
-rw-r--r--tests/mir-opt/dest-prop/simple.rs8
-rw-r--r--tests/mir-opt/dest-prop/union.rs2
-rw-r--r--tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff6
-rw-r--r--tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff6
-rw-r--r--tests/mir-opt/enum_opt.rs2
-rw-r--r--tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff6
-rw-r--r--tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff6
-rw-r--r--tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff6
-rw-r--r--tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff6
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff18
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff18
-rw-r--r--tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff4
-rw-r--r--tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff4
-rw-r--r--tests/mir-opt/gvn.rs1
-rw-r--r--tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff10
-rw-r--r--tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff10
-rw-r--r--tests/mir-opt/issue_72181.bar.built.after.mir4
-rw-r--r--tests/mir-opt/issue_72181.main.built.after.mir16
-rw-r--r--tests/mir-opt/issue_72181_1.f.built.after.mir6
-rw-r--r--tests/mir-opt/issue_91633.bar.built.after.mir14
-rw-r--r--tests/mir-opt/issue_91633.hey.built.after.mir8
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.32bit.mir82
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.64bit.mir82
-rw-r--r--tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff56
-rw-r--r--tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff56
-rw-r--r--tests/mir-opt/jump_threading.rs16
-rw-r--r--tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff26
-rw-r--r--tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff26
-rw-r--r--tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir16
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.rs2
-rw-r--r--tests/run-make/env-dep-info/Makefile19
-rw-r--r--tests/run-make/env-dep-info/correct_macro.d6
-rw-r--r--tests/run-make/env-dep-info/correct_main.d8
-rw-r--r--tests/run-make/env-dep-info/rmake.rs21
-rw-r--r--tests/run-make/extra-filename-with-temp-outputs/Makefile7
-rw-r--r--tests/run-make/extra-filename-with-temp-outputs/rmake.rs21
-rw-r--r--tests/run-make/ice-dep-cannot-find-dep/a.rs (renamed from tests/run-make/issue-83045/a.rs)0
-rw-r--r--tests/run-make/ice-dep-cannot-find-dep/b.rs (renamed from tests/run-make/issue-83045/b.rs)0
-rw-r--r--tests/run-make/ice-dep-cannot-find-dep/c.rs (renamed from tests/run-make/issue-83045/c.rs)0
-rw-r--r--tests/run-make/ice-dep-cannot-find-dep/rmake.rs38
-rw-r--r--tests/run-make/issue-83045/Makefile33
-rw-r--r--tests/run-make/issue-85019-moved-src-dir/Makefile28
-rw-r--r--tests/run-make/moved-src-dir-fingerprint-ice/main.rs (renamed from tests/run-make/issue-85019-moved-src-dir/main.rs)0
-rw-r--r--tests/run-make/moved-src-dir-fingerprint-ice/my_lib.rs (renamed from tests/run-make/issue-85019-moved-src-dir/my_lib.rs)0
-rw-r--r--tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs38
-rw-r--r--tests/run-make/rustc-macro-dep-files/Makefile11
-rw-r--r--tests/run-make/rustc-macro-dep-files/correct.d3
-rw-r--r--tests/run-make/rustc-macro-dep-files/rmake.rs14
-rw-r--r--tests/run-make/wasm-abi/foo.rs87
-rw-r--r--tests/run-make/wasm-abi/host.wat22
-rw-r--r--tests/run-make/wasm-abi/rmake.rs29
-rw-r--r--tests/rustdoc-json/impl-trait-precise-capturing.rs6
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout7
-rw-r--r--tests/rustdoc-ui/ice-assoc-type-loop-102154.rs (renamed from tests/rustdoc/issue-102154.rs)3
-rw-r--r--tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs (renamed from tests/rustdoc/issue-100620.rs)3
-rw-r--r--tests/rustdoc-ui/ice-unresolved-import-100241.rs (renamed from tests/rustdoc/issue-100241.rs)2
-rw-r--r--tests/rustdoc/attributes-inlining-108281.rs (renamed from tests/rustdoc/issue-108281.rs)0
-rw-r--r--tests/rustdoc/bold-tag-101743.rs (renamed from tests/rustdoc/issue-101743-bold-tag.rs)0
-rw-r--r--tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs (renamed from tests/rustdoc/issue-106421-not-internal.rs)5
-rw-r--r--tests/rustdoc/force-unstable-if-unmarked-106421.rs (renamed from tests/rustdoc/issue-106421.rs)4
-rw-r--r--tests/rustdoc/ice-associated-const-equality-105952.rs (renamed from tests/rustdoc/issue-105952.rs)1
-rw-r--r--tests/rustdoc/ice-intra-doc-links-107995.rs (renamed from tests/rustdoc/issue-107995.rs)0
-rw-r--r--tests/rustdoc/impl-trait-precise-capturing.rs14
-rw-r--r--tests/rustdoc/inline-impl-through-glob-import-100204.rs (renamed from tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs)1
-rw-r--r--tests/rustdoc/issue-106142.rs14
-rw-r--r--tests/rustdoc/macro-export-crate-root-108231.rs (renamed from tests/rustdoc/issue-108231.rs)0
-rw-r--r--tests/rustdoc/macro-rules-broken-intra-doc-106142.rs17
-rw-r--r--tests/rustdoc/multiple-foreigns-w-same-name-99734.rs (renamed from tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs)1
-rw-r--r--tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs (renamed from tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs)1
-rw-r--r--tests/rustdoc/multiple-mods-w-same-name-99734.rs (renamed from tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs)1
-rw-r--r--tests/rustdoc/multiple-structs-w-same-name-99221.rs (renamed from tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs)1
-rw-r--r--tests/rustdoc/overlapping-reexport-105735-2.rs (renamed from tests/rustdoc/issue-105735-overlapping-reexport-2.rs)1
-rw-r--r--tests/rustdoc/overlapping-reexport-105735.rs (renamed from tests/rustdoc/issue-105735-overlapping-reexport.rs)1
-rw-r--r--tests/rustdoc/pub-use-loop-107350.rs (renamed from tests/rustdoc/issue-107350.rs)0
-rw-r--r--tests/rustdoc/reexport-of-reexport-108679.rs (renamed from tests/rustdoc/issue-108679-reexport-of-reexport.rs)0
-rw-r--r--tests/ui/abi/numbers-arithmetic/return-float.rs61
-rw-r--r--tests/ui/abi/removed-wasm-abi.rs4
-rw-r--r--tests/ui/abi/removed-wasm-abi.stderr12
-rw-r--r--tests/ui/abi/unsupported.aarch64.stderr24
-rw-r--r--tests/ui/abi/unsupported.arm.stderr22
-rw-r--r--tests/ui/abi/unsupported.i686.stderr18
-rw-r--r--tests/ui/abi/unsupported.riscv32.stderr22
-rw-r--r--tests/ui/abi/unsupported.riscv64.stderr22
-rw-r--r--tests/ui/abi/unsupported.rs3
-rw-r--r--tests/ui/abi/unsupported.x64.stderr22
-rw-r--r--tests/ui/asm/aarch64/parse-error.stderr64
-rw-r--r--tests/ui/asm/binary_asm_labels.rs17
-rw-r--r--tests/ui/asm/binary_asm_labels.stderr43
-rw-r--r--tests/ui/asm/named-asm-labels.rs24
-rw-r--r--tests/ui/asm/named-asm-labels.stderr224
-rw-r--r--tests/ui/asm/parse-error.stderr40
-rw-r--r--tests/ui/asm/type-check-1.stderr24
-rw-r--r--tests/ui/asm/x86_64/x86_64_parse_error.stderr24
-rw-r--r--tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr160
-rw-r--r--tests/ui/attributes/issue-90873.stderr7
-rw-r--r--tests/ui/backtrace/synchronized-panic-handler.rs17
-rw-r--r--tests/ui/backtrace/synchronized-panic-handler.run.stderr5
-rw-r--r--tests/ui/borrowck/dbg-issue-120327.rs68
-rw-r--r--tests/ui/borrowck/dbg-issue-120327.stderr117
-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/issue-72408-nested-closures-exponential.rs3
-rw-r--r--tests/ui/closures/issue-72408-nested-closures-exponential.stderr10
-rw-r--r--tests/ui/codegen/overflow-during-mono.rs2
-rw-r--r--tests/ui/codegen/overflow-during-mono.stderr11
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-parse.stderr6
-rw-r--r--tests/ui/const-generics/legacy-const-generics-bad.stderr7
-rw-r--r--tests/ui/consts/const-eval/issue-104390.stderr27
-rw-r--r--tests/ui/consts/issue-3521.stderr8
-rw-r--r--tests/ui/consts/issue-91560.stderr16
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references.rs90
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references.stderr333
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.rs95
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.stderr308
-rw-r--r--tests/ui/consts/non-const-value-in-const.stderr17
-rw-r--r--tests/ui/consts/offset_from_ub.rs33
-rw-r--r--tests/ui/consts/offset_from_ub.stderr22
-rw-r--r--tests/ui/coverage-attr/bad-syntax.stderr11
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr18
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr18
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs25
-rw-r--r--tests/ui/did_you_mean/E0178.stderr21
-rw-r--r--tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr43
-rw-r--r--tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr43
-rw-r--r--tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr48
-rw-r--r--tests/ui/did_you_mean/issue-54109-without-witness.stderr48
-rw-r--r--tests/ui/did_you_mean/pub-macro-rules.stderr7
-rw-r--r--tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr14
-rw-r--r--tests/ui/did_you_mean/use_instead_of_import.stderr28
-rw-r--r--tests/ui/enum/nested-enum.rs9
-rw-r--r--tests/ui/enum/nested-enum.stderr31
-rw-r--r--tests/ui/error-codes/E0435.stderr7
-rw-r--r--tests/ui/error-codes/E0586.stderr7
-rw-r--r--tests/ui/expr/if/attrs/else-attrs.stderr9
-rw-r--r--tests/ui/extern/extern-const.stderr8
-rw-r--r--tests/ui/feature-gates/feature-gate-wasm_abi.rs26
-rw-r--r--tests/ui/feature-gates/feature-gate-wasm_abi.stderr73
-rw-r--r--tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-xop_target_feature.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-xop_target_feature.stderr13
-rw-r--r--tests/ui/fmt/format-string-error-2.stderr7
-rw-r--r--tests/ui/fn/fn-recover-return-sign.fixed4
-rw-r--r--tests/ui/fn/fn-recover-return-sign.stderr28
-rw-r--r--tests/ui/fn/fn-recover-return-sign2.stderr7
-rw-r--r--tests/ui/generics/issue-95208-ignore-qself.stderr9
-rw-r--r--tests/ui/generics/issue-95208.stderr9
-rw-r--r--tests/ui/generics/single-colon-path-not-const-generics.stderr6
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr34
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr42
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr56
-rw-r--r--tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr14
-rw-r--r--tests/ui/impl-trait/impl-trait-plus-priority.stderr70
-rw-r--r--tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr6
-rw-r--r--tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs30
-rw-r--r--tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr67
-rw-r--r--tests/ui/implied-bounds/dyn-erasure-no-tait.rs53
-rw-r--r--tests/ui/implied-bounds/dyn-erasure-tait.rs39
-rw-r--r--tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr41
-rw-r--r--tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr41
-rw-r--r--tests/ui/imports/suggest-import-ice-issue-127302.rs12
-rw-r--r--tests/ui/imports/suggest-import-issue-120074.edition2015.stderr (renamed from tests/ui/imports/suggest-import-issue-120074.stderr)2
-rw-r--r--tests/ui/imports/suggest-import-issue-120074.edition2021.stderr23
-rw-r--r--tests/ui/imports/suggest-import-issue-120074.rs2
-rw-r--r--tests/ui/issues/issue-22638.rs2
-rw-r--r--tests/ui/issues/issue-22638.stderr17
-rw-r--r--tests/ui/issues/issue-27433.fixed2
-rw-r--r--tests/ui/issues/issue-27433.rs2
-rw-r--r--tests/ui/issues/issue-27433.stderr9
-rw-r--r--tests/ui/issues/issue-3521-2.stderr9
-rw-r--r--tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr9
-rw-r--r--tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr9
-rw-r--r--tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs2
-rw-r--r--tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr8
-rw-r--r--tests/ui/issues/issue-40782.stderr14
-rw-r--r--tests/ui/issues/issue-44239.stderr8
-rw-r--r--tests/ui/iterators/issue-58952-filter-type-length.rs3
-rw-r--r--tests/ui/iterators/issue-58952-filter-type-length.stderr8
-rw-r--r--tests/ui/label/label_misspelled_2.stderr14
-rw-r--r--tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr7
-rw-r--r--tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs14
-rw-r--r--tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr17
-rw-r--r--tests/ui/macros/recovery-allowed.stderr9
-rw-r--r--tests/ui/malformed/malformed-special-attrs.stderr12
-rw-r--r--tests/ui/methods/filter-relevant-fn-bounds.rs23
-rw-r--r--tests/ui/methods/filter-relevant-fn-bounds.stderr74
-rw-r--r--tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs18
-rw-r--r--tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr90
-rw-r--r--tests/ui/moves/moved-value-on-as-ref-arg.fixed37
-rw-r--r--tests/ui/moves/moved-value-on-as-ref-arg.rs37
-rw-r--r--tests/ui/moves/moved-value-on-as-ref-arg.stderr79
-rw-r--r--tests/ui/object-safety/avoid-ice-on-warning.new.stderr7
-rw-r--r--tests/ui/object-safety/avoid-ice-on-warning.old.stderr7
-rw-r--r--tests/ui/operator-recovery/less-than-greater-than.stderr7
-rw-r--r--tests/ui/or-patterns/fn-param-wrap-parens.stderr7
-rw-r--r--tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr8
-rw-r--r--tests/ui/or-patterns/multiple-pattern-typo.stderr49
-rw-r--r--tests/ui/or-patterns/nested-undelimited-precedence.stderr35
-rw-r--r--tests/ui/or-patterns/or-patterns-syntactic-fail.stderr28
-rw-r--r--tests/ui/or-patterns/remove-leading-vert.fixed2
-rw-r--r--tests/ui/or-patterns/remove-leading-vert.stderr160
-rw-r--r--tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr93
-rw-r--r--tests/ui/parser/bad-char-literals.stderr28
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.stderr112
-rw-r--r--tests/ui/parser/byte-literals.stderr14
-rw-r--r--tests/ui/parser/char/whitespace-character-literal.stderr8
-rw-r--r--tests/ui/parser/default-on-wrong-item-kind.stderr8
-rw-r--r--tests/ui/parser/do-catch-suggests-try.stderr6
-rw-r--r--tests/ui/parser/doc-comment-in-if-statement.stderr9
-rw-r--r--tests/ui/parser/expr-rarrow-call.stderr30
-rw-r--r--tests/ui/parser/fn-colon-return-type.stderr7
-rw-r--r--tests/ui/parser/foreign-const-semantic-fail.stderr16
-rw-r--r--tests/ui/parser/foreign-const-syntactic-fail.stderr16
-rw-r--r--tests/ui/parser/ice-issue-127600.rs2
-rw-r--r--tests/ui/parser/ice-issue-127600.stderr8
-rw-r--r--tests/ui/parser/ident-recovery.stderr22
-rw-r--r--tests/ui/parser/if-in-in.stderr10
-rw-r--r--tests/ui/parser/impl-parsing.stderr14
-rw-r--r--tests/ui/parser/intersection-patterns-1.stderr12
-rw-r--r--tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs3
-rw-r--r--tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr7
-rw-r--r--tests/ui/parser/issues/issue-100197-mut-let.stderr7
-rw-r--r--tests/ui/parser/issues/issue-101477-enum.stderr7
-rw-r--r--tests/ui/parser/issues/issue-101477-let.stderr8
-rw-r--r--tests/ui/parser/issues/issue-108109-fn-missing-params.stderr14
-rw-r--r--tests/ui/parser/issues/issue-113203.stderr8
-rw-r--r--tests/ui/parser/issues/issue-118530-ice.stderr6
-rw-r--r--tests/ui/parser/issues/issue-17718-const-mut.stderr7
-rw-r--r--tests/ui/parser/issues/issue-23620-invalid-escapes.stderr9
-rw-r--r--tests/ui/parser/issues/issue-27255.stderr14
-rw-r--r--tests/ui/parser/issues/issue-32501.stderr7
-rw-r--r--tests/ui/parser/issues/issue-46186.stderr7
-rw-r--r--tests/ui/parser/issues/issue-48636.stderr5
-rw-r--r--tests/ui/parser/issues/issue-49040.stderr8
-rw-r--r--tests/ui/parser/issues/issue-52496.stderr7
-rw-r--r--tests/ui/parser/issues/issue-54521-2.stderr32
-rw-r--r--tests/ui/parser/issues/issue-54521-3.stderr32
-rw-r--r--tests/ui/parser/issues/issue-57684.stderr18
-rw-r--r--tests/ui/parser/issues/issue-57819.stderr56
-rw-r--r--tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr14
-rw-r--r--tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr14
-rw-r--r--tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr22
-rw-r--r--tests/ui/parser/issues/issue-70388-without-witness.stderr22
-rw-r--r--tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr8
-rw-r--r--tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr20
-rw-r--r--tests/ui/parser/issues/issue-89574.stderr7
-rw-r--r--tests/ui/parser/issues/issue-90993.stderr6
-rw-r--r--tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr7
-rw-r--r--tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr14
-rw-r--r--tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs3
-rw-r--r--tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr6
-rw-r--r--tests/ui/parser/item-free-const-no-body-semantic-fail.stderr7
-rw-r--r--tests/ui/parser/item-free-static-no-body-semantic-fail.stderr14
-rw-r--r--tests/ui/parser/item-kw-case-mismatch.stderr98
-rw-r--r--tests/ui/parser/label-after-block-like.stderr63
-rw-r--r--tests/ui/parser/labeled-no-colon-expr.stderr53
-rw-r--r--tests/ui/parser/let-binop.stderr21
-rw-r--r--tests/ui/parser/lifetime-in-pattern-recover.stderr16
-rw-r--r--tests/ui/parser/lifetime-in-pattern.stderr8
-rw-r--r--tests/ui/parser/macro/pub-item-macro.stderr7
-rw-r--r--tests/ui/parser/match-arm-without-body.stderr7
-rw-r--r--tests/ui/parser/match-arm-without-braces.stderr7
-rw-r--r--tests/ui/parser/mut-patterns.stderr61
-rw-r--r--tests/ui/parser/not-a-pred.stderr7
-rw-r--r--tests/ui/parser/pat-recover-wildcards.stderr7
-rw-r--r--tests/ui/parser/pub-method-macro.stderr7
-rw-r--r--tests/ui/parser/range-inclusive-extra-equals.stderr6
-rw-r--r--tests/ui/parser/range_inclusive.stderr7
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.stderr112
-rw-r--r--tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr13
-rw-r--r--tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr8
-rw-r--r--tests/ui/parser/recover/recover-range-pats.stderr188
-rw-r--r--tests/ui/parser/recover/recover-ref-dyn-mut.stderr7
-rw-r--r--tests/ui/parser/recover/recover-unticked-labels.stderr18
-rw-r--r--tests/ui/parser/regions-out-of-scope-slice.stderr9
-rw-r--r--tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr7
-rw-r--r--tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr7
-rw-r--r--tests/ui/parser/struct-default-values-and-missing-field-separator.stderr80
-rw-r--r--tests/ui/parser/suggest-assoc-const.stderr7
-rw-r--r--tests/ui/parser/trait-object-delimiters.stderr14
-rw-r--r--tests/ui/parser/trait-object-lifetime-parens.stderr16
-rw-r--r--tests/ui/parser/trait-object-polytrait-priority.rs1
-rw-r--r--tests/ui/parser/trait-object-polytrait-priority.stderr7
-rw-r--r--tests/ui/parser/unicode-character-literal.stderr8
-rw-r--r--tests/ui/parser/unmatched-langle-1.stderr8
-rw-r--r--tests/ui/parser/unnecessary-let.stderr23
-rw-r--r--tests/ui/parser/use-colon-as-mod-sep.stderr24
-rw-r--r--tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr18
-rw-r--r--tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr6
-rw-r--r--tests/ui/pattern/pattern-bad-ref-box-order.stderr7
-rw-r--r--tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr7
-rw-r--r--tests/ui/pub/pub-restricted.stderr30
-rw-r--r--tests/ui/range/impossible_range.stderr14
-rw-r--r--tests/ui/range/range-inclusive-pattern-precedence.stderr7
-rw-r--r--tests/ui/range/range-inclusive-pattern-precedence2.stderr7
-rw-r--r--tests/ui/recursion/issue-83150.rs2
-rw-r--r--tests/ui/recursion/issue-83150.stderr15
-rw-r--r--tests/ui/repeat-expr/repeat_count.stderr7
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr21
-rw-r--r--tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs24
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr64
-rw-r--r--tests/ui/self/self-vs-path-ambiguity.stderr8
-rw-r--r--tests/ui/self/self_type_keyword.stderr7
-rw-r--r--tests/ui/structs/struct-duplicate-comma.stderr11
-rw-r--r--tests/ui/structs/struct-field-init-syntax.stderr14
-rw-r--r--tests/ui/suggestions/const-no-type.stderr21
-rw-r--r--tests/ui/suggestions/js-style-comparison-op.stderr14
-rw-r--r--tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr21
-rw-r--r--tests/ui/suggestions/recover-invalid-float.stderr21
-rw-r--r--tests/ui/suggestions/type-ascription-instead-of-method.stderr6
-rw-r--r--tests/ui/suggestions/type-ascription-instead-of-path.stderr6
-rw-r--r--tests/ui/suggestions/type-ascription-instead-of-variant.stderr6
-rw-r--r--tests/ui/tool-attributes/invalid-tool.rs6
-rw-r--r--tests/ui/tool-attributes/invalid-tool.stderr8
-rw-r--r--tests/ui/traits/issue-91949-hangs-on-recursion.rs2
-rw-r--r--tests/ui/traits/issue-91949-hangs-on-recursion.stderr19
-rw-r--r--tests/ui/type/ascription/issue-47666.stderr6
-rw-r--r--tests/ui/type/ascription/issue-54516.stderr6
-rw-r--r--tests/ui/type/ascription/issue-60933.stderr6
-rw-r--r--tests/ui/type/pattern_types/bad_pat.stderr14
-rw-r--r--tests/ui/type/type-ascription-instead-of-statement-end.stderr6
-rw-r--r--tests/ui/type/type-ascription-with-fn-call.stderr6
-rw-r--r--tests/ui/type/type-dependent-def-issue-49241.stderr9
-rw-r--r--tests/ui/type_length_limit.rs2
-rw-r--r--tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr14
-rw-r--r--tests/ui/typeck/issue-79040.stderr7
-rw-r--r--tests/ui/typeof/issue-42060.stderr14
-rw-r--r--triagebot.toml20
1180 files changed, 19096 insertions, 11400 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4cf0e5fba53..8032154a736 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -65,7 +65,7 @@ jobs:
     defaults:
       run:
         shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}
-    timeout-minutes: 600
+    timeout-minutes: 240
     env:
       CI_JOB_NAME: ${{ matrix.image }}
       CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
diff --git a/Cargo.lock b/Cargo.lock
index afeb9faec09..cafc623c185 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3420,6 +3420,7 @@ version = "0.2.0"
 dependencies = [
  "ar",
  "bstr",
+ "build_helper",
  "gimli 0.28.1",
  "object 0.34.0",
  "regex",
@@ -3515,6 +3516,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84"
 
 [[package]]
+name = "rustc-stable-hash"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5c9f15eec8235d7cb775ee6f81891db79b98fd54ba1ad8fae565b88ef1ae4e2"
+
+[[package]]
 name = "rustc-std-workspace-alloc"
 version = "1.99.0"
 dependencies = [
@@ -3852,6 +3859,7 @@ dependencies = [
  "portable-atomic",
  "rustc-hash",
  "rustc-rayon",
+ "rustc-stable-hash",
  "rustc_arena",
  "rustc_graphviz",
  "rustc_index",
diff --git a/INSTALL.md b/INSTALL.md
index 1c2cecf8ef9..ded0b59fc6c 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -215,7 +215,7 @@ python x.py build
 
 Right now, building Rust only works with some known versions of Visual Studio.
 If you have a more recent version installed and the build system doesn't
-understand, you may need to force rustbuild to use an older version.
+understand, you may need to force bootstrap to use an older version.
 This can be done by manually calling the appropriate vcvars file before running
 the bootstrap.
 
diff --git a/RELEASES.md b/RELEASES.md
index 305da6a3550..0ecd472efb6 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,161 @@
+Version 1.80 (2024-07-25)
+==========================
+
+<a id="1.80-Language"></a>
+
+Language
+--------
+- [Document maximum allocation size](https://github.com/rust-lang/rust/pull/116675/)
+- [Allow zero-byte offsets and ZST read/writes on arbitrary pointers](https://github.com/rust-lang/rust/pull/117329/)
+- [Support C23's variadics without a named parameter](https://github.com/rust-lang/rust/pull/124048/)
+- [Stabilize `exclusive_range_pattern` feature](https://github.com/rust-lang/rust/pull/124459/)
+- [Guarantee layout and ABI of `Result` in some scenarios](https://github.com/rust-lang/rust/pull/124870)
+
+<a id="1.80-Compiler"></a>
+
+Compiler
+--------
+- [Update cc crate to v1.0.97 allowing additional spectre mitigations on MSVC targets](https://github.com/rust-lang/rust/pull/124892/)
+- [Allow field reordering on types marked `repr(packed(1))`](https://github.com/rust-lang/rust/pull/125360/)
+- [Add a lint against never type fallback affecting unsafe code](https://github.com/rust-lang/rust/pull/123939/)
+- [Disallow cast with trailing braced macro in let-else](https://github.com/rust-lang/rust/pull/125049/)
+- [Expand `for_loops_over_fallibles` lint to lint on fallibles behind references.](https://github.com/rust-lang/rust/pull/125156/)
+- [self-contained linker: retry linking without `-fuse-ld=lld` on CCs that don't support it](https://github.com/rust-lang/rust/pull/125417/)
+- [Do not parse CVarArgs (`...`) as a type in trait bounds](https://github.com/rust-lang/rust/pull/125863/)
+- Improvements to LLDB formatting [#124458](https://github.com/rust-lang/rust/pull/124458) [#124500](https://github.com/rust-lang/rust/pull/124500)
+- [For the wasm32-wasip2 target default to PIC and do not use `-fuse-ld=lld`](https://github.com/rust-lang/rust/pull/124858/)
+- [Add x86_64-unknown-linux-none as a tier 3 target](https://github.com/rust-lang/rust/pull/125023/)
+- [Lint on `foo.into_iter()` resolving to `&Box<[T]>: IntoIterator`](https://github.com/rust-lang/rust/pull/124097/)
+
+<a id="1.80-Libraries"></a>
+
+Libraries
+---------
+- [Add `size_of` and `size_of_val` and `align_of` and `align_of_val` to the prelude](https://github.com/rust-lang/rust/pull/123168/)
+- [Abort a process when FD ownership is violated](https://github.com/rust-lang/rust/pull/124210/)
+- [io::Write::write_fmt: panic if the formatter fails when the stream does not fail](https://github.com/rust-lang/rust/pull/125012/)
+- [Panic if `PathBuf::set_extension` would add a path separator](https://github.com/rust-lang/rust/pull/125070/)
+- [Add assert_unsafe_precondition to unchecked_{add,sub,neg,mul,shl,shr} methods](https://github.com/rust-lang/rust/pull/121571/)
+- [Update `c_char` on AIX to use the correct type](https://github.com/rust-lang/rust/pull/122986/)
+- [`offset_of!` no longer returns a temporary](https://github.com/rust-lang/rust/pull/124484/)
+- [Handle sigma in `str.to_lowercase` correctly](https://github.com/rust-lang/rust/pull/124773/)
+- [Raise `DEFAULT_MIN_STACK_SIZE` to at least 64KiB](https://github.com/rust-lang/rust/pull/126059/)
+
+<a id="1.80-Stabilized-APIs"></a>
+
+Stabilized APIs
+---------------
+- [`impl Default for Rc<CStr>`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3CCStr%3E)
+- [`impl Default for Rc<str>`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3Cstr%3E)
+- [`impl Default for Rc<[T]>`](https://doc.rust-lang.org/beta/alloc/rc/struct.Rc.html#impl-Default-for-Rc%3C%5BT%5D%3E)
+- [`impl Default for Arc<str>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3Cstr%3E)
+- [`impl Default for Arc<CStr>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3CCStr%3E)
+- [`impl Default for Arc<[T]>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3C%5BT%5D%3E)
+- [`impl IntoIterator for Box<[T]>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-IntoIterator-for-Box%3C%5BI%5D,+A%3E)
+- [`impl FromIterator<String> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E) 
+- [`impl FromIterator<char> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3Cchar%3E-for-Box%3Cstr%3E)
+- [`LazyCell`](https://doc.rust-lang.org/beta/core/cell/struct.LazyCell.html)
+- [`LazyLock`](https://doc.rust-lang.org/beta/std/sync/struct.LazyLock.html)
+- [`Duration::div_duration_f32`](https://doc.rust-lang.org/beta/std/time/struct.Duration.html#method.div_duration_f32)
+- [`Duration::div_duration_f64`](https://doc.rust-lang.org/beta/std/time/struct.Duration.html#method.div_duration_f64)
+- [`Option::take_if`](https://doc.rust-lang.org/beta/std/option/enum.Option.html#method.take_if)
+- [`Seek::seek_relative`](https://doc.rust-lang.org/beta/std/io/trait.Seek.html#method.seek_relative)
+- [`BinaryHeap::as_slice`](https://doc.rust-lang.org/beta/std/collections/struct.BinaryHeap.html#method.as_slice)
+- [`NonNull::offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset)
+- [`NonNull::byte_offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset)
+- [`NonNull::add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.add)
+- [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add)
+- [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub)
+- [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub)
+- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
+- [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from)
+- [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read)
+- [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile)
+- [`NonNull::read_unaligned`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_unaligned)
+- [`NonNull::write`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write)
+- [`NonNull::write_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_volatile)
+- [`NonNull::write_unaligned`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_unaligned)
+- [`NonNull::write_bytes`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.write_bytes)
+- [`NonNull::copy_to`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_to)
+- [`NonNull::copy_to_nonoverlapping`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_to_nonoverlapping)
+- [`NonNull::copy_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_from)
+- [`NonNull::copy_from_nonoverlapping`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.copy_from_nonoverlapping)
+- [`NonNull::replace`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.replace)
+- [`NonNull::swap`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.swap)
+- [`NonNull::drop_in_place`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.drop_in_place)
+- [`NonNull::align_offset`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.align_offset)
+- [`<[T]>::split_at_checked`](https://doc.rust-lang.org/beta/std/primitive.slice.html#method.split_at_checked)
+- [`<[T]>::split_at_mut_checked`](https://doc.rust-lang.org/beta/std/primitive.slice.html#method.split_at_mut_checked)
+- [`str::split_at_checked`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.split_at_checked)
+- [`str::split_at_mut_checked`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.split_at_mut_checked)
+- [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii)
+- [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start)
+- [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end)
+- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
+- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
+- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
+- [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS)
+- [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits)
+- [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits)
+- [`Ipv6Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#associatedconstant.BITS)
+- [`Ipv6Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#method.to_bits)
+- [`Ipv6Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv6Addr.html#method.from_bits)
+- [`Vec::<[T; N]>::into_flattened`](https://doc.rust-lang.org/beta/alloc/vec/struct.Vec.html#method.into_flattened)
+- [`<[[T; N]]>::as_flattened`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.as_flattened)
+- [`<[[T; N]]>::as_flattened_mut`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.as_flattened_mut)
+
+These APIs are now stable in const contexts:
+
+- [`<[T]>::last_chunk`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.last_chunk)
+- [`BinaryHeap::new`](https://doc.rust-lang.org/beta/std/collections/struct.BinaryHeap.html#method.new)
+
+<a id="1.80-Cargo"></a>
+
+Cargo
+-----
+- [Stabilize `-Zcheck-cfg` as always enabled](https://github.com/rust-lang/cargo/pull/13571/)
+- [Warn, rather than fail publish, if a target is excluded](https://github.com/rust-lang/cargo/pull/13713/)
+- [Add special `check-cfg` lint config for the `unexpected_cfgs` lint](https://github.com/rust-lang/cargo/pull/13913/)
+- [Stabilize `cargo update --precise <yanked>`](https://github.com/rust-lang/cargo/pull/13974/)
+- [Don't change file permissions on `Cargo.toml` when using `cargo add`](https://github.com/rust-lang/cargo/pull/13898/)
+- [Support using `cargo fix` on IPv6-only networks](https://github.com/rust-lang/cargo/pull/13907/)
+
+<a id="1.80-Rustdoc"></a>
+
+Rustdoc
+-----
+
+- [Allow searching for references](https://github.com/rust-lang/rust/pull/124148/)
+- [Stabilize `custom_code_classes_in_docs` feature](https://github.com/rust-lang/rust/pull/124577/)
+- [fix: In cross-crate scenarios show enum variants on type aliases of enums](https://github.com/rust-lang/rust/pull/125300/)
+
+<a id="1.80-Compatibility-Notes"></a>
+
+Compatibility Notes
+-------------------
+- [rustfmt estimates line lengths differently when using non-ascii characters](https://github.com/rust-lang/rustfmt/issues/6203)
+- [Type aliases are now handled correctly in orphan check](https://github.com/rust-lang/rust/pull/117164/)
+- [Allow instructing rustdoc to read from stdin via `-`](https://github.com/rust-lang/rust/pull/124611/)
+- [`std::env::{set_var, remove_var}` can no longer be converted to safe function pointers and no longer implement the `Fn` family of traits](https://github.com/rust-lang/rust/pull/124636)
+- [Warn (or error) when `Self` constructor from outer item is referenced in inner nested item](https://github.com/rust-lang/rust/pull/124187/)
+- [Turn `indirect_structural_match` and `pointer_structural_match` lints into hard errors](https://github.com/rust-lang/rust/pull/124661/)
+- [Make `where_clause_object_safety` lint a regular object safety violation](https://github.com/rust-lang/rust/pull/125380/)
+- [Turn `proc_macro_back_compat` lint into a hard error.](https://github.com/rust-lang/rust/pull/125596/)
+- [Detect unused structs even when implementing private traits](https://github.com/rust-lang/rust/pull/122382/)
+- [`std::sync::ReentrantLockGuard<T>` is no longer `Sync` if `T: !Sync`](https://github.com/rust-lang/rust/pull/125527) which means [`std::io::StdoutLock` and `std::io::StderrLock` are no longer Sync](https://github.com/rust-lang/rust/issues/127340)
+
+<a id="1.80-Internal-Changes"></a>
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- Misc improvements to size of generated html by rustdoc e.g. [#124738](https://github.com/rust-lang/rust/pull/124738/) and [#123734](https://github.com/rust-lang/rust/pull/123734/)
+- [MSVC targets no longer depend on libc](https://github.com/rust-lang/rust/pull/124050/)
+
 Version 1.79.0 (2024-06-13)
 ==========================
 
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 088ae9ba441..d2c7b1c0753 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -202,21 +202,18 @@ impl Attribute {
         }
     }
 
-    // Named `get_tokens` to distinguish it from the `<Attribute as HasTokens>::tokens` method.
-    pub fn get_tokens(&self) -> TokenStream {
-        match &self.kind {
-            AttrKind::Normal(normal) => TokenStream::new(
-                normal
-                    .tokens
-                    .as_ref()
-                    .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
-                    .to_attr_token_stream()
-                    .to_token_trees(),
-            ),
-            &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone(
+    pub fn token_trees(&self) -> Vec<TokenTree> {
+        match self.kind {
+            AttrKind::Normal(ref normal) => normal
+                .tokens
+                .as_ref()
+                .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
+                .to_attr_token_stream()
+                .to_token_trees(),
+            AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone(
                 token::DocComment(comment_kind, self.style, data),
                 self.span,
-            ),
+            )],
         }
     }
 }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index ee068f19332..a92ef575777 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -16,7 +16,7 @@
 use crate::ast::{AttrStyle, StmtKind};
 use crate::ast_traits::{HasAttrs, HasTokens};
 use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
-use crate::AttrVec;
+use crate::{AttrVec, Attribute};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{self, Lrc};
@@ -179,11 +179,10 @@ impl AttrTokenStream {
         AttrTokenStream(Lrc::new(tokens))
     }
 
-    /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`.
-    /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened'
-    /// back to a `TokenStream` of the form `outer_attr attr_target`.
-    /// If there are inner attributes, they are inserted into the proper
-    /// place in the attribute target tokens.
+    /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`. During
+    /// conversion, any `AttrTokenTree::AttrsTarget` gets "flattened" back to a
+    /// `TokenStream`, as described in the comment on
+    /// `attrs_and_tokens_to_token_trees`.
     pub fn to_token_trees(&self) -> Vec<TokenTree> {
         let mut res = Vec::with_capacity(self.0.len());
         for tree in self.0.iter() {
@@ -200,51 +199,7 @@ impl AttrTokenStream {
                     ))
                 }
                 AttrTokenTree::AttrsTarget(target) => {
-                    let idx = target
-                        .attrs
-                        .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer));
-                    let (outer_attrs, inner_attrs) = target.attrs.split_at(idx);
-
-                    let mut target_tokens = target.tokens.to_attr_token_stream().to_token_trees();
-                    if !inner_attrs.is_empty() {
-                        let mut found = false;
-                        // Check the last two trees (to account for a trailing semi)
-                        for tree in target_tokens.iter_mut().rev().take(2) {
-                            if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree {
-                                // Inner attributes are only supported on extern blocks, functions,
-                                // impls, and modules. All of these have their inner attributes
-                                // placed at the beginning of the rightmost outermost braced group:
-                                // e.g. fn foo() { #![my_attr] }
-                                //
-                                // Therefore, we can insert them back into the right location
-                                // without needing to do any extra position tracking.
-                                //
-                                // Note: Outline modules are an exception - they can
-                                // have attributes like `#![my_attr]` at the start of a file.
-                                // Support for custom attributes in this position is not
-                                // properly implemented - we always synthesize fake tokens,
-                                // so we never reach this code.
-
-                                let mut stream = TokenStream::default();
-                                for inner_attr in inner_attrs {
-                                    stream.push_stream(inner_attr.get_tokens());
-                                }
-                                stream.push_stream(delim_tokens.clone());
-                                *tree = TokenTree::Delimited(*span, *spacing, *delim, stream);
-                                found = true;
-                                break;
-                            }
-                        }
-
-                        assert!(
-                            found,
-                            "Failed to find trailing delimited group in: {target_tokens:?}"
-                        );
-                    }
-                    for attr in outer_attrs {
-                        res.extend(attr.get_tokens().0.iter().cloned());
-                    }
-                    res.extend(target_tokens);
+                    attrs_and_tokens_to_token_trees(&target.attrs, &target.tokens, &mut res);
                 }
             }
         }
@@ -252,15 +207,76 @@ impl AttrTokenStream {
     }
 }
 
+// Converts multiple attributes and the tokens for a target AST node into token trees, and appends
+// them to `res`.
+//
+// Example: if the AST node is "fn f() { blah(); }", then:
+// - Simple if no attributes are present, e.g. "fn f() { blah(); }"
+// - Simple if only outer attribute are present, e.g. "#[outer1] #[outer2] fn f() { blah(); }"
+// - Trickier if inner attributes are present, because they must be moved within the AST node's
+//   tokens, e.g. "#[outer] fn f() { #![inner] blah() }"
+fn attrs_and_tokens_to_token_trees(
+    attrs: &[Attribute],
+    target_tokens: &LazyAttrTokenStream,
+    res: &mut Vec<TokenTree>,
+) {
+    let idx = attrs.partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer));
+    let (outer_attrs, inner_attrs) = attrs.split_at(idx);
+
+    // Add outer attribute tokens.
+    for attr in outer_attrs {
+        res.extend(attr.token_trees());
+    }
+
+    // Add target AST node tokens.
+    res.extend(target_tokens.to_attr_token_stream().to_token_trees());
+
+    // Insert inner attribute tokens.
+    if !inner_attrs.is_empty() {
+        let mut found = false;
+        // Check the last two trees (to account for a trailing semi)
+        for tree in res.iter_mut().rev().take(2) {
+            if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree {
+                // Inner attributes are only supported on extern blocks, functions,
+                // impls, and modules. All of these have their inner attributes
+                // placed at the beginning of the rightmost outermost braced group:
+                // e.g. fn foo() { #![my_attr] }
+                //
+                // Therefore, we can insert them back into the right location
+                // without needing to do any extra position tracking.
+                //
+                // Note: Outline modules are an exception - they can
+                // have attributes like `#![my_attr]` at the start of a file.
+                // Support for custom attributes in this position is not
+                // properly implemented - we always synthesize fake tokens,
+                // so we never reach this code.
+                let mut tts = vec![];
+                for inner_attr in inner_attrs {
+                    tts.extend(inner_attr.token_trees());
+                }
+                tts.extend(delim_tokens.0.iter().cloned());
+                let stream = TokenStream::new(tts);
+                *tree = TokenTree::Delimited(*span, *spacing, *delim, stream);
+                found = true;
+                break;
+            }
+        }
+        assert!(found, "Failed to find trailing delimited group in: {res:?}");
+    }
+}
+
 /// Stores the tokens for an attribute target, along
 /// with its attributes.
 ///
 /// This is constructed during parsing when we need to capture
-/// tokens.
+/// tokens, for `cfg` and `cfg_attr` attributes.
 ///
 /// For example, `#[cfg(FALSE)] struct Foo {}` would
 /// have an `attrs` field containing the `#[cfg(FALSE)]` attr,
 /// and a `tokens` field storing the (unparsed) tokens `struct Foo {}`
+///
+/// The `cfg`/`cfg_attr` processing occurs in
+/// `StripUnconfigured::configure_tokens`.
 #[derive(Clone, Debug, Encodable, Decodable)]
 pub struct AttrsTarget {
     /// Attributes, both outer and inner.
@@ -437,18 +453,10 @@ impl TokenStream {
     }
 
     pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream {
-        let Some(tokens) = node.tokens() else {
-            panic!("missing tokens for node: {:?}", node);
-        };
-        let attrs = node.attrs();
-        let attr_stream = if attrs.is_empty() {
-            tokens.to_attr_token_stream()
-        } else {
-            let target =
-                AttrsTarget { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
-            AttrTokenStream::new(vec![AttrTokenTree::AttrsTarget(target)])
-        };
-        TokenStream::new(attr_stream.to_token_trees())
+        let tokens = node.tokens().unwrap_or_else(|| panic!("missing tokens for node: {:?}", node));
+        let mut tts = vec![];
+        attrs_and_tokens_to_token_trees(node.attrs(), tokens, &mut tts);
+        TokenStream::new(tts)
     }
 
     pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 9cf3182daea..2178b65727d 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -607,8 +607,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
     // does not check the same for lib features unless there's at least one
     // declared lang feature
     if !sess.opts.unstable_features.is_nightly_build() {
-        let lang_features = &features.declared_lang_features;
-        if lang_features.len() == 0 {
+        if features.declared_features.is_empty() {
             return;
         }
         for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
@@ -624,7 +623,8 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
                 attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
             {
                 let name = ident.name;
-                let stable_since = lang_features
+                let stable_since = features
+                    .declared_lang_features
                     .iter()
                     .flat_map(|&(feature, _, since)| if feature == name { since } else { None })
                     .next();
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 00a30dc2240..59b3c6916cb 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -553,7 +553,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, '_, 'tcx> {
                         panic!("could not find BorrowIndex for location {location:?}");
                     });
 
-                    trans.gen(index);
+                    trans.gen_(index);
                 }
 
                 // Make sure there are no remaining borrows for variables
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b1e302e5e27..c7f6840e401 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -4,7 +4,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 
 use either::Either;
-use hir::ClosureKind;
+use hir::{ClosureKind, Path};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
@@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::mir::VarDebugInfoContents;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
     FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
@@ -445,6 +446,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 } else {
                     (None, &[][..], 0)
                 };
+                let mut can_suggest_clone = true;
                 if let Some(def_id) = def_id
                     && let node = self.infcx.tcx.hir_node_by_def_id(def_id)
                     && let Some(fn_sig) = node.fn_sig()
@@ -452,24 +454,73 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
                     && let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
                 {
-                    let mut span: MultiSpan = arg.span.into();
-                    span.push_span_label(
-                        arg.span,
-                        "this parameter takes ownership of the value".to_string(),
-                    );
-                    let descr = match node.fn_kind() {
-                        Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",
-                        Some(hir::intravisit::FnKind::Method(..)) => "method",
-                        Some(hir::intravisit::FnKind::Closure) => "closure",
-                    };
-                    span.push_span_label(ident.span, format!("in this {descr}"));
-                    err.span_note(
-                        span,
-                        format!(
-                            "consider changing this parameter type in {descr} `{ident}` to borrow \
-                             instead if owning the value isn't necessary",
-                        ),
-                    );
+                    let mut is_mut = false;
+                    if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = arg.kind
+                        && let Res::Def(DefKind::TyParam, param_def_id) = path.res
+                        && self
+                            .infcx
+                            .tcx
+                            .predicates_of(def_id)
+                            .instantiate_identity(self.infcx.tcx)
+                            .predicates
+                            .into_iter()
+                            .any(|pred| {
+                                if let ty::ClauseKind::Trait(predicate) = pred.kind().skip_binder()
+                                    && [
+                                        self.infcx.tcx.get_diagnostic_item(sym::AsRef),
+                                        self.infcx.tcx.get_diagnostic_item(sym::AsMut),
+                                        self.infcx.tcx.get_diagnostic_item(sym::Borrow),
+                                        self.infcx.tcx.get_diagnostic_item(sym::BorrowMut),
+                                    ]
+                                    .contains(&Some(predicate.def_id()))
+                                    && let ty::Param(param) = predicate.self_ty().kind()
+                                    && let generics = self.infcx.tcx.generics_of(def_id)
+                                    && let param = generics.type_param(*param, self.infcx.tcx)
+                                    && param.def_id == param_def_id
+                                {
+                                    if [
+                                        self.infcx.tcx.get_diagnostic_item(sym::AsMut),
+                                        self.infcx.tcx.get_diagnostic_item(sym::BorrowMut),
+                                    ]
+                                    .contains(&Some(predicate.def_id()))
+                                    {
+                                        is_mut = true;
+                                    }
+                                    true
+                                } else {
+                                    false
+                                }
+                            })
+                    {
+                        // The type of the argument corresponding to the expression that got moved
+                        // is a type parameter `T`, which is has a `T: AsRef` obligation.
+                        err.span_suggestion_verbose(
+                            expr.span.shrink_to_lo(),
+                            "borrow the value to avoid moving it",
+                            format!("&{}", if is_mut { "mut " } else { "" }),
+                            Applicability::MachineApplicable,
+                        );
+                        can_suggest_clone = is_mut;
+                    } else {
+                        let mut span: MultiSpan = arg.span.into();
+                        span.push_span_label(
+                            arg.span,
+                            "this parameter takes ownership of the value".to_string(),
+                        );
+                        let descr = match node.fn_kind() {
+                            Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",
+                            Some(hir::intravisit::FnKind::Method(..)) => "method",
+                            Some(hir::intravisit::FnKind::Closure) => "closure",
+                        };
+                        span.push_span_label(ident.span, format!("in this {descr}"));
+                        err.span_note(
+                            span,
+                            format!(
+                                "consider changing this parameter type in {descr} `{ident}` to \
+                                 borrow instead if owning the value isn't necessary",
+                            ),
+                        );
+                    }
                 }
                 let place = &self.move_data.move_paths[mpi].place;
                 let ty = place.ty(self.body, self.infcx.tcx).ty;
@@ -487,15 +538,23 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                         ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),
                     ..
                 } = move_spans
+                    && can_suggest_clone
                 {
                     self.suggest_cloning(err, ty, expr, None, Some(move_spans));
-                } else if self.suggest_hoisting_call_outside_loop(err, expr) {
+                } else if self.suggest_hoisting_call_outside_loop(err, expr) && can_suggest_clone {
                     // The place where the type moves would be misleading to suggest clone.
                     // #121466
                     self.suggest_cloning(err, ty, expr, None, Some(move_spans));
                 }
             }
-            if let Some(pat) = finder.pat {
+
+            self.suggest_ref_for_dbg_args(expr, place, move_span, err);
+
+            // it's useless to suggest inserting `ref` when the span don't comes from local code
+            if let Some(pat) = finder.pat
+                && !move_span.is_dummy()
+                && !self.infcx.tcx.sess.source_map().is_imported(move_span)
+            {
                 *in_pattern = true;
                 let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
                 if let Some(pat) = finder.parent_pat {
@@ -510,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         }
     }
 
+    // for dbg!(x) which may take ownership, suggest dbg!(&x) instead
+    // but here we actually do not check whether the macro name is `dbg!`
+    // so that we may extend the scope a bit larger to cover more cases
+    fn suggest_ref_for_dbg_args(
+        &self,
+        body: &hir::Expr<'_>,
+        place: &Place<'tcx>,
+        move_span: Span,
+        err: &mut Diag<'infcx>,
+    ) {
+        let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
+            VarDebugInfoContents::Place(ref p) => p == place,
+            _ => false,
+        });
+        let arg_name = if let Some(var_info) = var_info {
+            var_info.name
+        } else {
+            return;
+        };
+        struct MatchArgFinder {
+            expr_span: Span,
+            match_arg_span: Option<Span>,
+            arg_name: Symbol,
+        }
+        impl Visitor<'_> for MatchArgFinder {
+            fn visit_expr(&mut self, e: &hir::Expr<'_>) {
+                // dbg! is expanded into a match pattern, we need to find the right argument span
+                if let hir::ExprKind::Match(expr, ..) = &e.kind
+                    && let hir::ExprKind::Path(hir::QPath::Resolved(
+                        _,
+                        path @ Path { segments: [seg], .. },
+                    )) = &expr.kind
+                    && seg.ident.name == self.arg_name
+                    && self.expr_span.source_callsite().contains(expr.span)
+                {
+                    self.match_arg_span = Some(path.span);
+                }
+                hir::intravisit::walk_expr(self, e);
+            }
+        }
+
+        let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
+        finder.visit_expr(body);
+        if let Some(macro_arg_span) = finder.match_arg_span {
+            err.span_suggestion_verbose(
+                macro_arg_span.shrink_to_lo(),
+                "consider borrowing instead of transferring ownership",
+                "&",
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     fn report_use_of_uninitialized(
         &self,
         mpi: MovePathIndex,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index d258c68b959..9ad941dabbe 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -821,6 +821,8 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
             | TerminatorKind::Return
             | TerminatorKind::TailCall { .. }
             | TerminatorKind::CoroutineDrop => {
+                // Returning from the function implicitly kills storage for all locals and statics.
+                // Often, the storage will already have been killed by an explicit
                 // StorageDead, but we don't always emit those (notably on unwind paths),
                 // so this "extra check" serves as a kind of backup.
                 let borrow_set = self.borrow_set.clone();
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 15c9e9d66fa..efec5db836b 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -16,9 +16,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 = "arbitrary"
@@ -67,7 +67,7 @@ dependencies = [
  "cranelift-entity",
  "cranelift-isle",
  "gimli",
- "hashbrown 0.14.3",
+ "hashbrown 0.14.5",
  "log",
  "regalloc2",
  "rustc-hash",
@@ -182,9 +182,9 @@ dependencies = [
 
 [[package]]
 name = "crc32fast"
-version = "1.4.0"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
 dependencies = [
  "cfg-if",
 ]
@@ -203,9 +203,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
 
 [[package]]
 name = "gimli"
-version = "0.28.0"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 dependencies = [
  "fallible-iterator",
  "indexmap",
@@ -223,9 +223,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 = [
  "ahash",
 ]
@@ -237,20 +237,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
 dependencies = [
  "equivalent",
- "hashbrown 0.14.3",
+ "hashbrown 0.14.5",
 ]
 
 [[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"
 
 [[package]]
 name = "libloading"
-version = "0.8.3"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
+checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
 dependencies = [
  "cfg-if",
  "windows-targets",
@@ -258,9 +258,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 = "mach"
@@ -273,9 +273,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 = "object"
@@ -284,7 +284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
 dependencies = [
  "crc32fast",
- "hashbrown 0.14.3",
+ "hashbrown 0.14.5",
  "indexmap",
  "memchr",
 ]
@@ -297,9 +297,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[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",
 ]
@@ -382,9 +382,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
 name = "syn"
-version = "2.0.60"
+version = "2.0.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -393,9 +393,9 @@ dependencies = [
 
 [[package]]
 name = "target-lexicon"
-version = "0.12.14"
+version = "0.12.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
+checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2"
 
 [[package]]
 name = "unicode-ident"
@@ -454,9 +454,9 @@ 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",
  "windows_aarch64_msvc",
@@ -470,66 +470,66 @@ dependencies = [
 
 [[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"
-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"
-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.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"
-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.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"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "zerocopy"
-version = "0.7.32"
+version = "0.7.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.7.32"
+version = "0.7.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index cfa91744a0e..db9b551bd2a 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-06-30"
+channel = "nightly-2024-07-13"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index c1b7e4b0e07..f0550c23b17 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -34,6 +34,7 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
 
 # vendor intrinsics
 rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic
+rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.round.ps
 
 # exotic linkages
 rm tests/incremental/hashes/function_interfaces.rs
@@ -56,13 +57,13 @@ rm -r tests/run-make/target-specs # i686 not supported by Cranelift
 rm -r tests/run-make/mismatching-target-triples # same
 rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
 rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
+rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes
 
 # requires LTO
 rm -r tests/run-make/cdylib
 rm -r tests/run-make/codegen-options-parsing
 rm -r tests/run-make/lto-*
 rm -r tests/run-make/reproducible-build-2
-rm -r tests/run-make/issue-109934-lto-debuginfo
 rm -r tests/run-make/no-builtins-lto
 rm -r tests/run-make/reachable-extern-fn-available-lto
 
@@ -109,6 +110,7 @@ rm -r tests/run-make/symbols-include-type-name
 rm -r tests/run-make/notify-all-emit-artifacts
 rm -r tests/run-make/reset-codegen-1
 rm -r tests/run-make/inline-always-many-cgu
+rm -r tests/run-make/intrinsic-unreachable
 
 # giving different but possibly correct results
 # =============================================
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 9dc94ab33ea..fa0de6f9de5 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -395,7 +395,6 @@ pub(crate) fn codegen_terminator_call<'tcx>(
             crate::intrinsics::codegen_llvm_intrinsic_call(
                 fx,
                 &fx.tcx.symbol_name(instance).name,
-                fn_args,
                 args,
                 ret_place,
                 target,
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index 414d3db1c51..3f23e0d9e04 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -14,12 +14,12 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
 
     fn create_dll_import_lib(
         &self,
-        _sess: &Session,
+        sess: &Session,
         _lib_name: &str,
         _dll_imports: &[rustc_session::cstore::DllImport],
         _tmpdir: &Path,
         _is_direct_dependency: bool,
     ) -> PathBuf {
-        unimplemented!("creating dll imports is not yet supported");
+        sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift");
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index fd34ed88c0b..0ba163f50ae 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -385,15 +385,43 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
 
         if let Some(section_name) = section_name {
             let (segment_name, section_name) = if tcx.sess.target.is_like_osx {
-                let section_name = section_name.as_str();
-                if let Some(names) = section_name.split_once(',') {
-                    names
-                } else {
+                // See https://github.com/llvm/llvm-project/blob/main/llvm/lib/MC/MCSectionMachO.cpp
+                let mut parts = section_name.as_str().split(',');
+                let Some(segment_name) = parts.next() else {
                     tcx.dcx().fatal(format!(
                         "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
                         section_name
                     ));
+                };
+                let Some(section_name) = parts.next() else {
+                    tcx.dcx().fatal(format!(
+                        "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
+                        section_name
+                    ));
+                };
+                if section_name.len() > 16 {
+                    tcx.dcx().fatal(format!(
+                        "#[link_section = \"{}\"] is not valid for macos target: section name bigger than 16 bytes",
+                        section_name
+                    ));
+                }
+                let section_type = parts.next().unwrap_or("regular");
+                if section_type != "regular" && section_type != "cstring_literals" {
+                    tcx.dcx().fatal(format!(
+                        "#[link_section = \"{}\"] is not supported: unsupported section type {}",
+                        section_name, section_type,
+                    ));
+                }
+                let _attrs = parts.next();
+                if parts.next().is_some() {
+                    tcx.dcx().fatal(format!(
+                        "#[link_section = \"{}\"] is not valid for macos target: too many components",
+                        section_name
+                    ));
                 }
+                // FIXME(bytecodealliance/wasmtime#8901) set S_CSTRING_LITERALS section type when
+                // cstring_literals is specified
+                (segment_name, section_name)
             } else {
                 ("", section_name.as_str())
             };
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
index 65f4c67b21f..1c6e471cc87 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
@@ -39,7 +39,13 @@ impl WriteDebugInfo for ObjectProduct {
         let section_id = self.object.add_section(
             segment,
             name,
-            if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
+            if id == SectionId::DebugStr || id == SectionId::DebugLineStr {
+                SectionKind::DebugString
+            } else if id == SectionId::EhFrame {
+                SectionKind::ReadOnlyData
+            } else {
+                SectionKind::Debug
+            },
         );
         self.object
             .section_mut(section_id)
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index e50c74b87f6..720a0d8fbf5 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -6,32 +6,16 @@ use crate::prelude::*;
 pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     intrinsic: &str,
-    generic_args: GenericArgsRef<'tcx>,
     args: &[Spanned<mir::Operand<'tcx>>],
     ret: CPlace<'tcx>,
     target: Option<BasicBlock>,
     span: Span,
 ) {
     if intrinsic.starts_with("llvm.aarch64") {
-        return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(
-            fx,
-            intrinsic,
-            generic_args,
-            args,
-            ret,
-            target,
-        );
+        return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(fx, intrinsic, args, ret, target);
     }
     if intrinsic.starts_with("llvm.x86") {
-        return llvm_x86::codegen_x86_llvm_intrinsic_call(
-            fx,
-            intrinsic,
-            generic_args,
-            args,
-            ret,
-            target,
-            span,
-        );
+        return llvm_x86::codegen_x86_llvm_intrinsic_call(fx, intrinsic, args, ret, target, span);
     }
 
     match intrinsic {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
index e66bcbf4e40..f0fb18608e0 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
@@ -6,7 +6,6 @@ use crate::prelude::*;
 pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     intrinsic: &str,
-    _args: GenericArgsRef<'tcx>,
     args: &[Spanned<mir::Operand<'tcx>>],
     ret: CPlace<'tcx>,
     target: Option<BasicBlock>,
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 399518e58d8..e1896138e48 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -10,7 +10,6 @@ use crate::prelude::*;
 pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     intrinsic: &str,
-    _args: GenericArgsRef<'tcx>,
     args: &[Spanned<mir::Operand<'tcx>>],
     ret: CPlace<'tcx>,
     target: Option<BasicBlock>,
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index a48c0a4450c..f47bfdad131 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -1,5 +1,5 @@
 #![feature(
-    no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types,
+    no_core, lang_items, intrinsics, unboxed_closures, extern_types,
     decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls,
     thread_local
 )]
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index cd82894af18..e7669470026 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -6,7 +6,6 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFuncti
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::{FunctionReturn, OptLevel};
 use rustc_span::symbol::sym;
-use rustc_target::spec::abi::Abi;
 use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
 use smallvec::SmallVec;
 
@@ -482,7 +481,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
         return;
     }
 
-    let mut function_features = function_features
+    let function_features = function_features
         .iter()
         .flat_map(|feat| {
             llvm_util::to_llvm_features(cx.tcx.sess, feat).into_iter().map(|f| format!("+{f}"))
@@ -504,17 +503,6 @@ pub fn from_fn_attrs<'ll, 'tcx>(
             let name = name.as_str();
             to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
         }
-
-        // The `"wasm"` abi on wasm targets automatically enables the
-        // `+multivalue` feature because the purpose of the wasm abi is to match
-        // the WebAssembly specification, which has this feature. This won't be
-        // needed when LLVM enables this `multivalue` feature by default.
-        if !cx.tcx.is_closure_like(instance.def_id()) {
-            let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi();
-            if abi == Abi::Wasm {
-                function_features.push("+multivalue".to_string());
-            }
-        }
     }
 
     let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index b969fe27a99..14a94468587 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -66,8 +66,15 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
         // For each expression ID that is directly used by one or more mappings,
         // mark it as not-yet-seen. This indicates that we expect to see a
         // corresponding `ExpressionUsed` statement during MIR traversal.
-        for term in function_coverage_info.mappings.iter().flat_map(|m| m.kind.terms()) {
-            if let CovTerm::Expression(id) = term {
+        for mapping in function_coverage_info.mappings.iter() {
+            // Currently we only worry about ordinary code mappings.
+            // For branch and MC/DC mappings, expressions might not correspond
+            // to any particular point in the control-flow graph.
+            // (Keep this in sync with the injection of `ExpressionUsed`
+            // statements in the `InstrumentCoverage` MIR pass.)
+            if let MappingKind::Code(term) = mapping.kind
+                && let CovTerm::Expression(id) = term
+            {
                 expressions_seen.remove(id);
             }
         }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 08e9e312827..e0bf6110cdf 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2057,7 +2057,7 @@ extern "C" {
         AddrOpsCount: c_uint,
         DL: &'a DILocation,
         InsertAtEnd: &'a BasicBlock,
-    ) -> &'a Value;
+    );
 
     pub fn LLVMRustDIBuilderCreateEnumerator<'a>(
         Builder: &DIBuilder<'a>,
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 2bd5dfdce83..dd134ebbe6b 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -398,7 +398,7 @@ impl<'a> GccLinker<'a> {
             self.link_arg("-dylib");
 
             // Note that the `osx_rpath_install_name` option here is a hack
-            // purely to support rustbuild right now, we should get a more
+            // purely to support bootstrap right now, we should get a more
             // principled solution at some point to force the compiler to pass
             // the right `-Wl,-install_name` with an `@rpath` in it.
             if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name {
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index bcddfe9fb9c..cea164df617 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -80,6 +80,8 @@ 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::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics,
+                Some(sym::xop_target_feature) => rust_features.xop_target_feature,
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index d86f1a7a34f..b227565f8f9 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -20,7 +20,7 @@ use super::{
     err_inval, err_ub_custom, err_unsup_format, memory::MemoryKind, throw_inval, throw_ub_custom,
     throw_ub_format, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg, ConstAllocation,
     GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic,
-    Scalar,
+    Provenance, Scalar,
 };
 
 use crate::fluent_generated as fluent;
@@ -259,25 +259,28 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                             // This will always return 0.
                             (a, b)
                         }
-                        (Err(_), _) | (_, Err(_)) => {
-                            // We managed to find a valid allocation for one pointer, but not the other.
-                            // That means they are definitely not pointing to the same allocation.
+                        _ if M::Provenance::OFFSET_IS_ADDR && a.addr() == b.addr() => {
+                            // At least one of the pointers has provenance, but they also point to
+                            // the same address so it doesn't matter; this is fine. `(0, 0)` means
+                            // we pass all the checks below and return 0.
+                            (0, 0)
+                        }
+                        // From here onwards, the pointers are definitely for different addresses
+                        // (or we can't determine their absolute address).
+                        (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _)))
+                            if a_alloc_id == b_alloc_id =>
+                        {
+                            // Found allocation for both, and it's the same.
+                            // Use these offsets for distance calculation.
+                            (a_offset.bytes(), b_offset.bytes())
+                        }
+                        _ => {
+                            // Not into the same allocation -- this is UB.
                             throw_ub_custom!(
                                 fluent::const_eval_offset_from_different_allocations,
                                 name = intrinsic_name,
                             );
                         }
-                        (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => {
-                            // Found allocation for both. They must be into the same allocation.
-                            if a_alloc_id != b_alloc_id {
-                                throw_ub_custom!(
-                                    fluent::const_eval_offset_from_different_allocations,
-                                    name = intrinsic_name,
-                                );
-                            }
-                            // Use these offsets for distance calculation.
-                            (a_offset.bytes(), b_offset.bytes())
-                        }
                     };
 
                 // Compute distance.
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index baaee67e787..33c25b746cc 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -995,13 +995,25 @@ where
     }
 
     /// Returns a wide MPlace of type `str` to a new 1-aligned allocation.
+    /// Immutable strings are deduplicated and stored in global memory.
     pub fn allocate_str(
         &mut self,
         str: &str,
         kind: MemoryKind<M::MemoryKind>,
         mutbl: Mutability,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
-        let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?;
+        let tcx = self.tcx.tcx;
+
+        // Use cache for immutable strings.
+        let ptr = if mutbl.is_not() {
+            // Use dedup'd allocation function.
+            let id = tcx.allocate_bytes_dedup(str.as_bytes());
+
+            // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation.
+            M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind))?
+        } else {
+            self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?
+        };
         let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self);
         let layout = self.layout_of(self.tcx.types.str_).unwrap();
         Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout))
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index c4b2e067bbe..e5e733439ea 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -15,6 +15,7 @@ jobserver_crate = { version = "0.1.28", package = "jobserver" }
 measureme = "11"
 rustc-hash = "1.1.0"
 rustc-rayon = { version = "0.5.0", optional = true }
+rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
 rustc_arena = { path = "../rustc_arena" }
 rustc_graphviz = { path = "../rustc_graphviz" }
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index 1bee159489d..30e3d6aa86c 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -1,5 +1,5 @@
 use crate::stable_hasher::impl_stable_traits_for_trivial_type;
-use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult};
+use crate::stable_hasher::{FromStableHash, Hash64, StableHasherHash};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::hash::{Hash, Hasher};
 
@@ -154,10 +154,11 @@ impl FingerprintHasher for crate::unhash::Unhasher {
     }
 }
 
-impl StableHasherResult for Fingerprint {
+impl FromStableHash for Fingerprint {
+    type Hash = StableHasherHash;
+
     #[inline]
-    fn finish(hasher: StableHasher) -> Self {
-        let (_0, _1) = hasher.finalize();
+    fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self {
         Fingerprint(_0, _1)
     }
 }
diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs
index 1564eeb4bae..ef5d2e845ef 100644
--- a/compiler/rustc_data_structures/src/hashes.rs
+++ b/compiler/rustc_data_structures/src/hashes.rs
@@ -11,7 +11,7 @@
 //! connect the fact that they can only be produced by a `StableHasher` to their
 //! `Encode`/`Decode` impls.
 
-use crate::stable_hasher::{StableHasher, StableHasherResult};
+use crate::stable_hasher::{FromStableHash, StableHasherHash};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt;
 use std::ops::BitXorAssign;
@@ -56,10 +56,12 @@ impl<D: Decoder> Decodable<D> for Hash64 {
     }
 }
 
-impl StableHasherResult for Hash64 {
+impl FromStableHash for Hash64 {
+    type Hash = StableHasherHash;
+
     #[inline]
-    fn finish(hasher: StableHasher) -> Self {
-        Self { inner: hasher.finalize().0 }
+    fn from(StableHasherHash([_0, __1]): Self::Hash) -> Self {
+        Self { inner: _0 }
     }
 }
 
@@ -121,10 +123,11 @@ impl<D: Decoder> Decodable<D> for Hash128 {
     }
 }
 
-impl StableHasherResult for Hash128 {
+impl FromStableHash for Hash128 {
+    type Hash = StableHasherHash;
+
     #[inline]
-    fn finish(hasher: StableHasher) -> Self {
-        let (_0, _1) = hasher.finalize();
+    fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self {
         Self { inner: u128::from(_0) | (u128::from(_1) << 64) }
     }
 }
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 356ddf014be..3f18b036940 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -24,7 +24,6 @@
 #![feature(core_intrinsics)]
 #![feature(extend_one)]
 #![feature(hash_raw_entry)]
-#![feature(hasher_prefixfree_extras)]
 #![feature(macro_metavar_expr)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
@@ -67,7 +66,6 @@ pub mod owned_slice;
 pub mod packed;
 pub mod profiling;
 pub mod sharded;
-pub mod sip128;
 pub mod small_c_str;
 pub mod snapshot_map;
 pub mod sorted_map;
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
deleted file mode 100644
index 812ed410a94..00000000000
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ /dev/null
@@ -1,505 +0,0 @@
-//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes.
-
-// This code is very hot and uses lots of arithmetic, avoid overflow checks for performance.
-// See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727
-use rustc_serialize::int_overflow::{DebugStrictAdd, DebugStrictSub};
-use std::hash::Hasher;
-use std::mem::{self, MaybeUninit};
-use std::ptr;
-
-#[cfg(test)]
-mod tests;
-
-// The SipHash algorithm operates on 8-byte chunks.
-const ELEM_SIZE: usize = mem::size_of::<u64>();
-
-// Size of the buffer in number of elements, not including the spill.
-//
-// The selection of this size was guided by rustc-perf benchmark comparisons of
-// different buffer sizes. It should be periodically reevaluated as the compiler
-// implementation and input characteristics change.
-//
-// Using the same-sized buffer for everything we hash is a performance versus
-// complexity tradeoff. The ideal buffer size, and whether buffering should even
-// be used, depends on what is being hashed. It may be worth it to size the
-// buffer appropriately (perhaps by making SipHasher128 generic over the buffer
-// size) or disable buffering depending on what is being hashed. But at this
-// time, we use the same buffer size for everything.
-const BUFFER_CAPACITY: usize = 8;
-
-// Size of the buffer in bytes, not including the spill.
-const BUFFER_SIZE: usize = BUFFER_CAPACITY * ELEM_SIZE;
-
-// Size of the buffer in number of elements, including the spill.
-const BUFFER_WITH_SPILL_CAPACITY: usize = BUFFER_CAPACITY + 1;
-
-// Size of the buffer in bytes, including the spill.
-const BUFFER_WITH_SPILL_SIZE: usize = BUFFER_WITH_SPILL_CAPACITY * ELEM_SIZE;
-
-// Index of the spill element in the buffer.
-const BUFFER_SPILL_INDEX: usize = BUFFER_WITH_SPILL_CAPACITY - 1;
-
-#[derive(Debug, Clone)]
-#[repr(C)]
-pub struct SipHasher128 {
-    // The access pattern during hashing consists of accesses to `nbuf` and
-    // `buf` until the buffer is full, followed by accesses to `state` and
-    // `processed`, and then repetition of that pattern until hashing is done.
-    // This is the basis for the ordering of fields below. However, in practice
-    // the cache miss-rate for data access is extremely low regardless of order.
-    nbuf: usize, // how many bytes in buf are valid
-    buf: [MaybeUninit<u64>; BUFFER_WITH_SPILL_CAPACITY], // unprocessed bytes le
-    state: State, // hash State
-    processed: usize, // how many bytes we've processed
-}
-
-#[derive(Debug, Clone, Copy)]
-#[repr(C)]
-struct State {
-    // v0, v2 and v1, v3 show up in pairs in the algorithm,
-    // and simd implementations of SipHash will use vectors
-    // of v02 and v13. By placing them in this order in the struct,
-    // the compiler can pick up on just a few simd optimizations by itself.
-    v0: u64,
-    v2: u64,
-    v1: u64,
-    v3: u64,
-}
-
-macro_rules! compress {
-    ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }};
-    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{
-        $v0 = $v0.wrapping_add($v1);
-        $v2 = $v2.wrapping_add($v3);
-        $v1 = $v1.rotate_left(13);
-        $v1 ^= $v0;
-        $v3 = $v3.rotate_left(16);
-        $v3 ^= $v2;
-        $v0 = $v0.rotate_left(32);
-
-        $v2 = $v2.wrapping_add($v1);
-        $v0 = $v0.wrapping_add($v3);
-        $v1 = $v1.rotate_left(17);
-        $v1 ^= $v2;
-        $v3 = $v3.rotate_left(21);
-        $v3 ^= $v0;
-        $v2 = $v2.rotate_left(32);
-    }};
-}
-
-// Copies up to 8 bytes from source to destination. This performs better than
-// `ptr::copy_nonoverlapping` on microbenchmarks and may perform better on real
-// workloads since all of the copies have fixed sizes and avoid calling memcpy.
-//
-// This is specifically designed for copies of up to 8 bytes, because that's the
-// maximum of number bytes needed to fill an 8-byte-sized element on which
-// SipHash operates. Note that for variable-sized copies which are known to be
-// less than 8 bytes, this function will perform more work than necessary unless
-// the compiler is able to optimize the extra work away.
-#[inline]
-unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) {
-    debug_assert!(count <= 8);
-
-    unsafe {
-        if count == 8 {
-            ptr::copy_nonoverlapping(src, dst, 8);
-            return;
-        }
-
-        let mut i = 0;
-        if i.debug_strict_add(3) < count {
-            ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4);
-            i = i.debug_strict_add(4);
-        }
-
-        if i.debug_strict_add(1) < count {
-            ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2);
-            i = i.debug_strict_add(2)
-        }
-
-        if i < count {
-            *dst.add(i) = *src.add(i);
-            i = i.debug_strict_add(1);
-        }
-
-        debug_assert_eq!(i, count);
-    }
-}
-
-// # Implementation
-//
-// This implementation uses buffering to reduce the hashing cost for inputs
-// consisting of many small integers. Buffering simplifies the integration of
-// integer input--the integer write function typically just appends to the
-// buffer with a statically sized write, updates metadata, and returns.
-//
-// Buffering also prevents alternating between writes that do and do not trigger
-// the hashing process. Only when the entire buffer is full do we transition
-// into hashing. This allows us to keep the hash state in registers for longer,
-// instead of loading and storing it before and after processing each element.
-//
-// When a write fills the buffer, a buffer processing function is invoked to
-// hash all of the buffered input. The buffer processing functions are marked
-// `#[inline(never)]` so that they aren't inlined into the append functions,
-// which ensures the more frequently called append functions remain inlineable
-// and don't include register pushing/popping that would only be made necessary
-// by inclusion of the complex buffer processing path which uses those
-// registers.
-//
-// The buffer includes a "spill"--an extra element at the end--which simplifies
-// the integer write buffer processing path. The value that fills the buffer can
-// be written with a statically sized write that may spill over into the spill.
-// After the buffer is processed, the part of the value that spilled over can be
-// written from the spill to the beginning of the buffer with another statically
-// sized write. This write may copy more bytes than actually spilled over, but
-// we maintain the metadata such that any extra copied bytes will be ignored by
-// subsequent processing. Due to the static sizes, this scheme performs better
-// than copying the exact number of bytes needed into the end and beginning of
-// the buffer.
-//
-// The buffer is uninitialized, which improves performance, but may preclude
-// efficient implementation of alternative approaches. The improvement is not so
-// large that an alternative approach should be disregarded because it cannot be
-// efficiently implemented with an uninitialized buffer. On the other hand, an
-// uninitialized buffer may become more important should a larger one be used.
-//
-// # Platform Dependence
-//
-// The SipHash algorithm operates on byte sequences. It parses the input stream
-// as 8-byte little-endian integers. Therefore, given the same byte sequence, it
-// produces the same result on big- and little-endian hardware.
-//
-// However, the Hasher trait has methods which operate on multi-byte integers.
-// How they are converted into byte sequences can be endian-dependent (by using
-// native byte order) or independent (by consistently using either LE or BE byte
-// order). It can also be `isize` and `usize` size dependent (by using the
-// native size), or independent (by converting to a common size), supposing the
-// values can be represented in 32 bits.
-//
-// In order to make `SipHasher128` consistent with `SipHasher` in libstd, we
-// choose to do the integer to byte sequence conversion in the platform-
-// dependent way. Clients can achieve platform-independent hashing by widening
-// `isize` and `usize` integers to 64 bits on 32-bit systems and byte-swapping
-// integers on big-endian systems before passing them to the writing functions.
-// This causes the input byte sequence to look identical on big- and little-
-// endian systems (supposing `isize` and `usize` values can be represented in 32
-// bits), which ensures platform-independent results.
-impl SipHasher128 {
-    #[inline]
-    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 {
-        let mut hasher = SipHasher128 {
-            nbuf: 0,
-            buf: [MaybeUninit::uninit(); BUFFER_WITH_SPILL_CAPACITY],
-            state: State {
-                v0: key0 ^ 0x736f6d6570736575,
-                // The XOR with 0xee is only done on 128-bit algorithm version.
-                v1: key1 ^ (0x646f72616e646f6d ^ 0xee),
-                v2: key0 ^ 0x6c7967656e657261,
-                v3: key1 ^ 0x7465646279746573,
-            },
-            processed: 0,
-        };
-
-        unsafe {
-            // Initialize spill because we read from it in `short_write_process_buffer`.
-            *hasher.buf.get_unchecked_mut(BUFFER_SPILL_INDEX) = MaybeUninit::zeroed();
-        }
-
-        hasher
-    }
-
-    #[inline]
-    pub fn short_write<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
-        let nbuf = self.nbuf;
-        debug_assert!(LEN <= 8);
-        debug_assert!(nbuf < BUFFER_SIZE);
-        debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
-
-        if nbuf.debug_strict_add(LEN) < BUFFER_SIZE {
-            unsafe {
-                // The memcpy call is optimized away because the size is known.
-                let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
-                ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
-            }
-
-            self.nbuf = nbuf.debug_strict_add(LEN);
-
-            return;
-        }
-
-        unsafe { self.short_write_process_buffer(bytes) }
-    }
-
-    // A specialized write function for values with size <= 8 that should only
-    // be called when the write would cause the buffer to fill.
-    //
-    // SAFETY: the write of `x` into `self.buf` starting at byte offset
-    // `self.nbuf` must cause `self.buf` to become fully initialized (and not
-    // overflow) if it wasn't already.
-    #[inline(never)]
-    unsafe fn short_write_process_buffer<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
-        unsafe {
-            let nbuf = self.nbuf;
-            debug_assert!(LEN <= 8);
-            debug_assert!(nbuf < BUFFER_SIZE);
-            debug_assert!(nbuf + LEN >= BUFFER_SIZE);
-            debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
-
-            // Copy first part of input into end of buffer, possibly into spill
-            // element. The memcpy call is optimized away because the size is known.
-            let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
-            ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
-
-            // Process buffer.
-            for i in 0..BUFFER_CAPACITY {
-                let elem = self.buf.get_unchecked(i).assume_init().to_le();
-                self.state.v3 ^= elem;
-                Sip13Rounds::c_rounds(&mut self.state);
-                self.state.v0 ^= elem;
-            }
-
-            // Copy remaining input into start of buffer by copying LEN - 1
-            // elements from spill (at most LEN - 1 bytes could have overflowed
-            // into the spill). The memcpy call is optimized away because the size
-            // is known. And the whole copy is optimized away for LEN == 1.
-            let dst = self.buf.as_mut_ptr() as *mut u8;
-            let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
-            ptr::copy_nonoverlapping(src, dst, LEN - 1);
-
-            // This function should only be called when the write fills the buffer.
-            // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
-            // LEN is statically known, so the branch is optimized away.
-            self.nbuf =
-                if LEN == 1 { 0 } else { nbuf.debug_strict_add(LEN).debug_strict_sub(BUFFER_SIZE) };
-            self.processed = self.processed.debug_strict_add(BUFFER_SIZE);
-        }
-    }
-
-    // A write function for byte slices.
-    #[inline]
-    fn slice_write(&mut self, msg: &[u8]) {
-        let length = msg.len();
-        let nbuf = self.nbuf;
-        debug_assert!(nbuf < BUFFER_SIZE);
-
-        if nbuf.debug_strict_add(length) < BUFFER_SIZE {
-            unsafe {
-                let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
-
-                if length <= 8 {
-                    copy_nonoverlapping_small(msg.as_ptr(), dst, length);
-                } else {
-                    // This memcpy is *not* optimized away.
-                    ptr::copy_nonoverlapping(msg.as_ptr(), dst, length);
-                }
-            }
-
-            self.nbuf = nbuf.debug_strict_add(length);
-
-            return;
-        }
-
-        unsafe { self.slice_write_process_buffer(msg) }
-    }
-
-    // A write function for byte slices that should only be called when the
-    // write would cause the buffer to fill.
-    //
-    // SAFETY: `self.buf` must be initialized up to the byte offset `self.nbuf`,
-    // and `msg` must contain enough bytes to initialize the rest of the element
-    // containing the byte offset `self.nbuf`.
-    #[inline(never)]
-    unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) {
-        unsafe {
-            let length = msg.len();
-            let nbuf = self.nbuf;
-            debug_assert!(nbuf < BUFFER_SIZE);
-            debug_assert!(nbuf + length >= BUFFER_SIZE);
-
-            // Always copy first part of input into current element of buffer.
-            // This function should only be called when the write fills the buffer,
-            // so we know that there is enough input to fill the current element.
-            let valid_in_elem = nbuf % ELEM_SIZE;
-            let needed_in_elem = ELEM_SIZE.debug_strict_sub(valid_in_elem);
-
-            let src = msg.as_ptr();
-            let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
-            copy_nonoverlapping_small(src, dst, needed_in_elem);
-
-            // Process buffer.
-
-            // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) /
-            // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0.
-            // We know that is true, because last step ensured we have a full
-            // element in the buffer.
-            let last = (nbuf / ELEM_SIZE).debug_strict_add(1);
-
-            for i in 0..last {
-                let elem = self.buf.get_unchecked(i).assume_init().to_le();
-                self.state.v3 ^= elem;
-                Sip13Rounds::c_rounds(&mut self.state);
-                self.state.v0 ^= elem;
-            }
-
-            // Process the remaining element-sized chunks of input.
-            let mut processed = needed_in_elem;
-            let input_left = length.debug_strict_sub(processed);
-            let elems_left = input_left / ELEM_SIZE;
-            let extra_bytes_left = input_left % ELEM_SIZE;
-
-            for _ in 0..elems_left {
-                let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le();
-                self.state.v3 ^= elem;
-                Sip13Rounds::c_rounds(&mut self.state);
-                self.state.v0 ^= elem;
-                processed = processed.debug_strict_add(ELEM_SIZE);
-            }
-
-            // Copy remaining input into start of buffer.
-            let src = msg.as_ptr().add(processed);
-            let dst = self.buf.as_mut_ptr() as *mut u8;
-            copy_nonoverlapping_small(src, dst, extra_bytes_left);
-
-            self.nbuf = extra_bytes_left;
-            self.processed = self.processed.debug_strict_add(nbuf.debug_strict_add(processed));
-        }
-    }
-
-    #[inline]
-    pub fn finish128(mut self) -> (u64, u64) {
-        debug_assert!(self.nbuf < BUFFER_SIZE);
-
-        // Process full elements in buffer.
-        let last = self.nbuf / ELEM_SIZE;
-
-        // Since we're consuming self, avoid updating members for a potential
-        // performance gain.
-        let mut state = self.state;
-
-        for i in 0..last {
-            let elem = unsafe { self.buf.get_unchecked(i).assume_init().to_le() };
-            state.v3 ^= elem;
-            Sip13Rounds::c_rounds(&mut state);
-            state.v0 ^= elem;
-        }
-
-        // Get remaining partial element.
-        let elem = if self.nbuf % ELEM_SIZE != 0 {
-            unsafe {
-                // Ensure element is initialized by writing zero bytes. At most
-                // `ELEM_SIZE - 1` are required given the above check. It's safe
-                // to write this many because we have the spill and we maintain
-                // `self.nbuf` such that this write will start before the spill.
-                let dst = (self.buf.as_mut_ptr() as *mut u8).add(self.nbuf);
-                ptr::write_bytes(dst, 0, ELEM_SIZE - 1);
-                self.buf.get_unchecked(last).assume_init().to_le()
-            }
-        } else {
-            0
-        };
-
-        // Finalize the hash.
-        let length = self.processed.debug_strict_add(self.nbuf);
-        let b: u64 = ((length as u64 & 0xff) << 56) | elem;
-
-        state.v3 ^= b;
-        Sip13Rounds::c_rounds(&mut state);
-        state.v0 ^= b;
-
-        state.v2 ^= 0xee;
-        Sip13Rounds::d_rounds(&mut state);
-        let _0 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3;
-
-        state.v1 ^= 0xdd;
-        Sip13Rounds::d_rounds(&mut state);
-        let _1 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3;
-
-        (_0, _1)
-    }
-}
-
-impl Hasher for SipHasher128 {
-    #[inline]
-    fn write_u8(&mut self, i: u8) {
-        self.short_write(i.to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_u16(&mut self, i: u16) {
-        self.short_write(i.to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_u32(&mut self, i: u32) {
-        self.short_write(i.to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_u64(&mut self, i: u64) {
-        self.short_write(i.to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_usize(&mut self, i: usize) {
-        self.short_write(i.to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_i8(&mut self, i: i8) {
-        self.short_write((i as u8).to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_i16(&mut self, i: i16) {
-        self.short_write((i as u16).to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_i32(&mut self, i: i32) {
-        self.short_write((i as u32).to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_i64(&mut self, i: i64) {
-        self.short_write((i as u64).to_ne_bytes());
-    }
-
-    #[inline]
-    fn write_isize(&mut self, i: isize) {
-        self.short_write((i as usize).to_ne_bytes());
-    }
-
-    #[inline]
-    fn write(&mut self, msg: &[u8]) {
-        self.slice_write(msg);
-    }
-
-    #[inline]
-    fn write_str(&mut self, s: &str) {
-        // This hasher works byte-wise, and `0xFF` cannot show up in a `str`,
-        // so just hashing the one extra byte is enough to be prefix-free.
-        self.write(s.as_bytes());
-        self.write_u8(0xFF);
-    }
-
-    fn finish(&self) -> u64 {
-        panic!("SipHasher128 cannot provide valid 64 bit hashes")
-    }
-}
-
-#[derive(Debug, Clone, Default)]
-struct Sip13Rounds;
-
-impl Sip13Rounds {
-    #[inline]
-    fn c_rounds(state: &mut State) {
-        compress!(state);
-    }
-
-    #[inline]
-    fn d_rounds(state: &mut State) {
-        compress!(state);
-        compress!(state);
-        compress!(state);
-    }
-}
diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs
deleted file mode 100644
index e9dd0f1176b..00000000000
--- a/compiler/rustc_data_structures/src/sip128/tests.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-use super::*;
-
-use std::hash::Hash;
-
-// Hash just the bytes of the slice, without length prefix
-struct Bytes<'a>(&'a [u8]);
-
-impl<'a> Hash for Bytes<'a> {
-    #[allow(unused_must_use)]
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        for byte in self.0 {
-            state.write_u8(*byte);
-        }
-    }
-}
-
-fn hash_with<T: Hash>(mut st: SipHasher128, x: &T) -> (u64, u64) {
-    x.hash(&mut st);
-    st.finish128()
-}
-
-fn hash<T: Hash>(x: &T) -> (u64, u64) {
-    hash_with(SipHasher128::new_with_keys(0, 0), x)
-}
-#[rustfmt::skip]
-const TEST_VECTOR: [[u8; 16]; 64] = [
-    [0xe7, 0x7e, 0xbc, 0xb2, 0x27, 0x88, 0xa5, 0xbe, 0xfd, 0x62, 0xdb, 0x6a, 0xdd, 0x30, 0x30, 0x01],
-    [0xfc, 0x6f, 0x37, 0x04, 0x60, 0xd3, 0xed, 0xa8, 0x5e, 0x05, 0x73, 0xcc, 0x2b, 0x2f, 0xf0, 0x63],
-    [0x75, 0x78, 0x7f, 0x09, 0x05, 0x69, 0x83, 0x9b, 0x85, 0x5b, 0xc9, 0x54, 0x8c, 0x6a, 0xea, 0x95],
-    [0x6b, 0xc5, 0xcc, 0xfa, 0x1e, 0xdc, 0xf7, 0x9f, 0x48, 0x23, 0x18, 0x77, 0x12, 0xeb, 0xd7, 0x43],
-    [0x0c, 0x78, 0x4e, 0x71, 0xac, 0x2b, 0x28, 0x5a, 0x9f, 0x8e, 0x92, 0xe7, 0x8f, 0xbf, 0x2c, 0x25],
-    [0xf3, 0x28, 0xdb, 0x89, 0x34, 0x5b, 0x62, 0x0c, 0x79, 0x52, 0x29, 0xa4, 0x26, 0x95, 0x84, 0x3e],
-    [0xdc, 0xd0, 0x3d, 0x29, 0xf7, 0x43, 0xe7, 0x10, 0x09, 0x51, 0xb0, 0xe8, 0x39, 0x85, 0xa6, 0xf8],
-    [0x10, 0x84, 0xb9, 0x23, 0xf2, 0xaa, 0xe0, 0xc3, 0xa6, 0x2f, 0x2e, 0xc8, 0x08, 0x48, 0xab, 0x77],
-    [0xaa, 0x12, 0xfe, 0xe1, 0xd5, 0xe3, 0xda, 0xb4, 0x72, 0x4f, 0x16, 0xab, 0x35, 0xf9, 0xc7, 0x99],
-    [0x81, 0xdd, 0xb8, 0x04, 0x2c, 0xf3, 0x39, 0x94, 0xf4, 0x72, 0x0e, 0x00, 0x94, 0x13, 0x7c, 0x42],
-    [0x4f, 0xaa, 0x54, 0x1d, 0x5d, 0x49, 0x8e, 0x89, 0xba, 0x0e, 0xa4, 0xc3, 0x87, 0xb2, 0x2f, 0xb4],
-    [0x72, 0x3b, 0x9a, 0xf3, 0x55, 0x44, 0x91, 0xdb, 0xb1, 0xd6, 0x63, 0x3d, 0xfc, 0x6e, 0x0c, 0x4e],
-    [0xe5, 0x3f, 0x92, 0x85, 0x9e, 0x48, 0x19, 0xa8, 0xdc, 0x06, 0x95, 0x73, 0x9f, 0xea, 0x8c, 0x65],
-    [0xb2, 0xf8, 0x58, 0xc7, 0xc9, 0xea, 0x80, 0x1d, 0x53, 0xd6, 0x03, 0x59, 0x6d, 0x65, 0x78, 0x44],
-    [0x87, 0xe7, 0x62, 0x68, 0xdb, 0xc9, 0x22, 0x72, 0x26, 0xb0, 0xca, 0x66, 0x5f, 0x64, 0xe3, 0x78],
-    [0xc1, 0x7e, 0x55, 0x05, 0xb2, 0xbd, 0x52, 0x6c, 0x29, 0x21, 0xcd, 0xec, 0x1e, 0x7e, 0x01, 0x09],
-    [0xd0, 0xa8, 0xd9, 0x57, 0x15, 0x51, 0x8e, 0xeb, 0xb5, 0x13, 0xb0, 0xf8, 0x3d, 0x9e, 0x17, 0x93],
-    [0x23, 0x41, 0x26, 0xf9, 0x3f, 0xbb, 0x66, 0x8d, 0x97, 0x51, 0x12, 0xe8, 0xfe, 0xbd, 0xf7, 0xec],
-    [0xef, 0x42, 0xf0, 0x3d, 0xb7, 0x8f, 0x70, 0x4d, 0x02, 0x3c, 0x44, 0x9f, 0x16, 0xb7, 0x09, 0x2b],
-    [0xab, 0xf7, 0x62, 0x38, 0xc2, 0x0a, 0xf1, 0x61, 0xb2, 0x31, 0x4b, 0x4d, 0x55, 0x26, 0xbc, 0xe9],
-    [0x3c, 0x2c, 0x2f, 0x11, 0xbb, 0x90, 0xcf, 0x0b, 0xe3, 0x35, 0xca, 0x9b, 0x2e, 0x91, 0xe9, 0xb7],
-    [0x2a, 0x7a, 0x68, 0x0f, 0x22, 0xa0, 0x2a, 0x92, 0xf4, 0x51, 0x49, 0xd2, 0x0f, 0xec, 0xe0, 0xef],
-    [0xc9, 0xa8, 0xd1, 0x30, 0x23, 0x1d, 0xd4, 0x3e, 0x42, 0xe6, 0x45, 0x69, 0x57, 0xf8, 0x37, 0x79],
-    [0x1d, 0x12, 0x7b, 0x84, 0x40, 0x5c, 0xea, 0xb9, 0x9f, 0xd8, 0x77, 0x5a, 0x9b, 0xe6, 0xc5, 0x59],
-    [0x9e, 0x4b, 0xf8, 0x37, 0xbc, 0xfd, 0x92, 0xca, 0xce, 0x09, 0xd2, 0x06, 0x1a, 0x84, 0xd0, 0x4a],
-    [0x39, 0x03, 0x1a, 0x96, 0x5d, 0x73, 0xb4, 0xaf, 0x5a, 0x27, 0x4d, 0x18, 0xf9, 0x73, 0xb1, 0xd2],
-    [0x7f, 0x4d, 0x0a, 0x12, 0x09, 0xd6, 0x7e, 0x4e, 0xd0, 0x6f, 0x75, 0x38, 0xe1, 0xcf, 0xad, 0x64],
-    [0xe6, 0x1e, 0xe2, 0x40, 0xfb, 0xdc, 0xce, 0x38, 0x96, 0x9f, 0x4c, 0xd2, 0x49, 0x27, 0xdd, 0x93],
-    [0x4c, 0x3b, 0xa2, 0xb3, 0x7b, 0x0f, 0xdd, 0x8c, 0xfa, 0x5e, 0x95, 0xc1, 0x89, 0xb2, 0x94, 0x14],
-    [0xe0, 0x6f, 0xd4, 0xca, 0x06, 0x6f, 0xec, 0xdd, 0x54, 0x06, 0x8a, 0x5a, 0xd8, 0x89, 0x6f, 0x86],
-    [0x5c, 0xa8, 0x4c, 0x34, 0x13, 0x9c, 0x65, 0x80, 0xa8, 0x8a, 0xf2, 0x49, 0x90, 0x72, 0x07, 0x06],
-    [0x42, 0xea, 0x96, 0x1c, 0x5b, 0x3c, 0x85, 0x8b, 0x17, 0xc3, 0xe5, 0x50, 0xdf, 0xa7, 0x90, 0x10],
-    [0x40, 0x6c, 0x44, 0xde, 0xe6, 0x78, 0x57, 0xb2, 0x94, 0x31, 0x60, 0xf3, 0x0c, 0x74, 0x17, 0xd3],
-    [0xc5, 0xf5, 0x7b, 0xae, 0x13, 0x20, 0xfc, 0xf4, 0xb4, 0xe8, 0x68, 0xe7, 0x1d, 0x56, 0xc6, 0x6b],
-    [0x04, 0xbf, 0x73, 0x7a, 0x5b, 0x67, 0x6b, 0xe7, 0xc3, 0xde, 0x05, 0x01, 0x7d, 0xf4, 0xbf, 0xf9],
-    [0x51, 0x63, 0xc9, 0xc0, 0x3f, 0x19, 0x07, 0xea, 0x10, 0x44, 0xed, 0x5c, 0x30, 0x72, 0x7b, 0x4f],
-    [0x37, 0xa1, 0x10, 0xf0, 0x02, 0x71, 0x8e, 0xda, 0xd2, 0x4b, 0x3f, 0x9e, 0xe4, 0x53, 0xf1, 0x40],
-    [0xb9, 0x87, 0x7e, 0x38, 0x1a, 0xed, 0xd3, 0xda, 0x08, 0xc3, 0x3e, 0x75, 0xff, 0x23, 0xac, 0x10],
-    [0x7c, 0x50, 0x04, 0x00, 0x5e, 0xc5, 0xda, 0x4c, 0x5a, 0xc9, 0x44, 0x0e, 0x5c, 0x72, 0x31, 0x93],
-    [0x81, 0xb8, 0x24, 0x37, 0x83, 0xdb, 0xc6, 0x46, 0xca, 0x9d, 0x0c, 0xd8, 0x2a, 0xbd, 0xb4, 0x6c],
-    [0x50, 0x57, 0x20, 0x54, 0x3e, 0xb9, 0xb4, 0x13, 0xd5, 0x0b, 0x3c, 0xfa, 0xd9, 0xee, 0xf9, 0x38],
-    [0x94, 0x5f, 0x59, 0x4d, 0xe7, 0x24, 0x11, 0xe4, 0xd3, 0x35, 0xbe, 0x87, 0x44, 0x56, 0xd8, 0xf3],
-    [0x37, 0x92, 0x3b, 0x3e, 0x37, 0x17, 0x77, 0xb2, 0x11, 0x70, 0xbf, 0x9d, 0x7e, 0x62, 0xf6, 0x02],
-    [0x3a, 0xd4, 0xe7, 0xc8, 0x57, 0x64, 0x96, 0x46, 0x11, 0xeb, 0x0a, 0x6c, 0x4d, 0x62, 0xde, 0x56],
-    [0xcd, 0x91, 0x39, 0x6c, 0x44, 0xaf, 0x4f, 0x51, 0x85, 0x57, 0x8d, 0x9d, 0xd9, 0x80, 0x3f, 0x0a],
-    [0xfe, 0x28, 0x15, 0x8e, 0x72, 0x7b, 0x86, 0x8f, 0x39, 0x03, 0xc9, 0xac, 0xda, 0x64, 0xa2, 0x58],
-    [0x40, 0xcc, 0x10, 0xb8, 0x28, 0x8c, 0xe5, 0xf0, 0xbc, 0x3a, 0xc0, 0xb6, 0x8a, 0x0e, 0xeb, 0xc8],
-    [0x6f, 0x14, 0x90, 0xf5, 0x40, 0x69, 0x9a, 0x3c, 0xd4, 0x97, 0x44, 0x20, 0xec, 0xc9, 0x27, 0x37],
-    [0xd5, 0x05, 0xf1, 0xb7, 0x5e, 0x1a, 0x84, 0xa6, 0x03, 0xc4, 0x35, 0x83, 0xb2, 0xed, 0x03, 0x08],
-    [0x49, 0x15, 0x73, 0xcf, 0xd7, 0x2b, 0xb4, 0x68, 0x2b, 0x7c, 0xa5, 0x88, 0x0e, 0x1c, 0x8d, 0x6f],
-    [0x3e, 0xd6, 0x9c, 0xfe, 0x45, 0xab, 0x40, 0x3f, 0x2f, 0xd2, 0xad, 0x95, 0x9b, 0xa2, 0x76, 0x66],
-    [0x8b, 0xe8, 0x39, 0xef, 0x1b, 0x20, 0xb5, 0x7c, 0x83, 0xba, 0x7e, 0xb6, 0xa8, 0xc2, 0x2b, 0x6a],
-    [0x14, 0x09, 0x18, 0x6a, 0xb4, 0x22, 0x31, 0xfe, 0xde, 0xe1, 0x81, 0x62, 0xcf, 0x1c, 0xb4, 0xca],
-    [0x2b, 0xf3, 0xcc, 0xc2, 0x4a, 0xb6, 0x72, 0xcf, 0x15, 0x1f, 0xb8, 0xd2, 0xf3, 0xf3, 0x06, 0x9b],
-    [0xb9, 0xb9, 0x3a, 0x28, 0x82, 0xd6, 0x02, 0x5c, 0xdb, 0x8c, 0x56, 0xfa, 0x13, 0xf7, 0x53, 0x7b],
-    [0xd9, 0x7c, 0xca, 0x36, 0x94, 0xfb, 0x20, 0x6d, 0xb8, 0xbd, 0x1f, 0x36, 0x50, 0xc3, 0x33, 0x22],
-    [0x94, 0xec, 0x2e, 0x19, 0xa4, 0x0b, 0xe4, 0x1a, 0xf3, 0x94, 0x0d, 0x6b, 0x30, 0xc4, 0x93, 0x84],
-    [0x4b, 0x41, 0x60, 0x3f, 0x20, 0x9a, 0x04, 0x5b, 0xe1, 0x40, 0xa3, 0x41, 0xa3, 0xdf, 0xfe, 0x10],
-    [0x23, 0xfb, 0xcb, 0x30, 0x9f, 0x1c, 0xf0, 0x94, 0x89, 0x07, 0x55, 0xab, 0x1b, 0x42, 0x65, 0x69],
-    [0xe7, 0xd9, 0xb6, 0x56, 0x90, 0x91, 0x8a, 0x2b, 0x23, 0x2f, 0x2f, 0x5c, 0x12, 0xc8, 0x30, 0x0e],
-    [0xad, 0xe8, 0x3c, 0xf7, 0xe7, 0xf3, 0x84, 0x7b, 0x36, 0xfa, 0x4b, 0x54, 0xb0, 0x0d, 0xce, 0x61],
-    [0x06, 0x10, 0xc5, 0xf2, 0xee, 0x57, 0x1c, 0x8a, 0xc8, 0x0c, 0xbf, 0xe5, 0x38, 0xbd, 0xf1, 0xc7],
-    [0x27, 0x1d, 0x5d, 0x00, 0xfb, 0xdb, 0x5d, 0x15, 0x5d, 0x9d, 0xce, 0xa9, 0x7c, 0xb4, 0x02, 0x18],
-    [0x4c, 0x58, 0x00, 0xe3, 0x4e, 0xfe, 0x42, 0x6f, 0x07, 0x9f, 0x6b, 0x0a, 0xa7, 0x52, 0x60, 0xad],
-];
-
-#[test]
-fn test_siphash_1_3_test_vector() {
-    let k0 = 0x_07_06_05_04_03_02_01_00;
-    let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08;
-
-    let mut input: Vec<u8> = Vec::new();
-
-    for i in 0..64 {
-        let out = hash_with(SipHasher128::new_with_keys(k0, k1), &Bytes(&input[..]));
-        let expected = (
-            ((TEST_VECTOR[i][0] as u64) << 0)
-                | ((TEST_VECTOR[i][1] as u64) << 8)
-                | ((TEST_VECTOR[i][2] as u64) << 16)
-                | ((TEST_VECTOR[i][3] as u64) << 24)
-                | ((TEST_VECTOR[i][4] as u64) << 32)
-                | ((TEST_VECTOR[i][5] as u64) << 40)
-                | ((TEST_VECTOR[i][6] as u64) << 48)
-                | ((TEST_VECTOR[i][7] as u64) << 56),
-            ((TEST_VECTOR[i][8] as u64) << 0)
-                | ((TEST_VECTOR[i][9] as u64) << 8)
-                | ((TEST_VECTOR[i][10] as u64) << 16)
-                | ((TEST_VECTOR[i][11] as u64) << 24)
-                | ((TEST_VECTOR[i][12] as u64) << 32)
-                | ((TEST_VECTOR[i][13] as u64) << 40)
-                | ((TEST_VECTOR[i][14] as u64) << 48)
-                | ((TEST_VECTOR[i][15] as u64) << 56),
-        );
-
-        assert_eq!(out, expected);
-        input.push(i as u8);
-    }
-}
-
-#[test]
-#[cfg(target_arch = "arm")]
-fn test_hash_usize() {
-    let val = 0xdeadbeef_deadbeef_u64;
-    assert!(hash(&(val as u64)) != hash(&(val as usize)));
-    assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
-}
-#[test]
-#[cfg(target_arch = "x86_64")]
-fn test_hash_usize() {
-    let val = 0xdeadbeef_deadbeef_u64;
-    assert_eq!(hash(&(val as u64)), hash(&(val as usize)));
-    assert!(hash(&(val as u32)) != hash(&(val as usize)));
-}
-#[test]
-#[cfg(target_arch = "x86")]
-fn test_hash_usize() {
-    let val = 0xdeadbeef_deadbeef_u64;
-    assert!(hash(&(val as u64)) != hash(&(val as usize)));
-    assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
-}
-
-#[test]
-fn test_hash_idempotent() {
-    let val64 = 0xdeadbeef_deadbeef_u64;
-    assert_eq!(hash(&val64), hash(&val64));
-    let val32 = 0xdeadbeef_u32;
-    assert_eq!(hash(&val32), hash(&val32));
-}
-
-#[test]
-fn test_hash_no_bytes_dropped_64() {
-    let val = 0xdeadbeef_deadbeef_u64;
-
-    assert!(hash(&val) != hash(&zero_byte(val, 0)));
-    assert!(hash(&val) != hash(&zero_byte(val, 1)));
-    assert!(hash(&val) != hash(&zero_byte(val, 2)));
-    assert!(hash(&val) != hash(&zero_byte(val, 3)));
-    assert!(hash(&val) != hash(&zero_byte(val, 4)));
-    assert!(hash(&val) != hash(&zero_byte(val, 5)));
-    assert!(hash(&val) != hash(&zero_byte(val, 6)));
-    assert!(hash(&val) != hash(&zero_byte(val, 7)));
-
-    fn zero_byte(val: u64, byte: usize) -> u64 {
-        assert!(byte < 8);
-        val & !(0xff << (byte * 8))
-    }
-}
-
-#[test]
-fn test_hash_no_bytes_dropped_32() {
-    let val = 0xdeadbeef_u32;
-
-    assert!(hash(&val) != hash(&zero_byte(val, 0)));
-    assert!(hash(&val) != hash(&zero_byte(val, 1)));
-    assert!(hash(&val) != hash(&zero_byte(val, 2)));
-    assert!(hash(&val) != hash(&zero_byte(val, 3)));
-
-    fn zero_byte(val: u32, byte: usize) -> u32 {
-        assert!(byte < 4);
-        val & !(0xff << (byte * 8))
-    }
-}
-
-#[test]
-fn test_hash_no_concat_alias() {
-    let s = ("aa", "bb");
-    let t = ("aabb", "");
-    let u = ("a", "abb");
-
-    assert!(s != t && t != u);
-    assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u));
-
-    let u = [1, 0, 0, 0];
-    let v = (&u[..1], &u[1..3], &u[3..]);
-    let w = (&u[..], &u[4..4], &u[4..4]);
-
-    assert!(v != w);
-    assert!(hash(&v) != hash(&w));
-}
-
-#[test]
-fn test_short_write_works() {
-    let test_u8 = 0xFF_u8;
-    let test_u16 = 0x1122_u16;
-    let test_u32 = 0x22334455_u32;
-    let test_u64 = 0x33445566_778899AA_u64;
-    let test_u128 = 0x11223344_55667788_99AABBCC_DDEEFF77_u128;
-    let test_usize = 0xD0C0B0A0_usize;
-
-    let test_i8 = -1_i8;
-    let test_i16 = -2_i16;
-    let test_i32 = -3_i32;
-    let test_i64 = -4_i64;
-    let test_i128 = -5_i128;
-    let test_isize = -6_isize;
-
-    let mut h1 = SipHasher128::new_with_keys(0, 0);
-    h1.write(b"bytes");
-    h1.write(b"string");
-    h1.write_u8(test_u8);
-    h1.write_u16(test_u16);
-    h1.write_u32(test_u32);
-    h1.write_u64(test_u64);
-    h1.write_u128(test_u128);
-    h1.write_usize(test_usize);
-    h1.write_i8(test_i8);
-    h1.write_i16(test_i16);
-    h1.write_i32(test_i32);
-    h1.write_i64(test_i64);
-    h1.write_i128(test_i128);
-    h1.write_isize(test_isize);
-
-    let mut h2 = SipHasher128::new_with_keys(0, 0);
-    h2.write(b"bytes");
-    h2.write(b"string");
-    h2.write(&test_u8.to_ne_bytes());
-    h2.write(&test_u16.to_ne_bytes());
-    h2.write(&test_u32.to_ne_bytes());
-    h2.write(&test_u64.to_ne_bytes());
-    h2.write(&test_u128.to_ne_bytes());
-    h2.write(&test_usize.to_ne_bytes());
-    h2.write(&test_i8.to_ne_bytes());
-    h2.write(&test_i16.to_ne_bytes());
-    h2.write(&test_i32.to_ne_bytes());
-    h2.write(&test_i64.to_ne_bytes());
-    h2.write(&test_i128.to_ne_bytes());
-    h2.write(&test_isize.to_ne_bytes());
-
-    let h1_hash = h1.finish128();
-    let h2_hash = h2.finish128();
-
-    assert_eq!(h1_hash, h2_hash);
-}
-
-macro_rules! test_fill_buffer {
-    ($type:ty, $write_method:ident) => {{
-        // Test filling and overfilling the buffer from all possible offsets
-        // for a given integer type and its corresponding write method.
-        const SIZE: usize = std::mem::size_of::<$type>();
-        let input = [42; BUFFER_SIZE];
-        let x = 0x01234567_89ABCDEF_76543210_FEDCBA98_u128 as $type;
-        let x_bytes = &x.to_ne_bytes();
-
-        for i in 1..=SIZE {
-            let s = &input[..BUFFER_SIZE - i];
-
-            let mut h1 = SipHasher128::new_with_keys(7, 13);
-            h1.write(s);
-            h1.$write_method(x);
-
-            let mut h2 = SipHasher128::new_with_keys(7, 13);
-            h2.write(s);
-            h2.write(x_bytes);
-
-            let h1_hash = h1.finish128();
-            let h2_hash = h2.finish128();
-
-            assert_eq!(h1_hash, h2_hash);
-        }
-    }};
-}
-
-#[test]
-fn test_fill_buffer() {
-    test_fill_buffer!(u8, write_u8);
-    test_fill_buffer!(u16, write_u16);
-    test_fill_buffer!(u32, write_u32);
-    test_fill_buffer!(u64, write_u64);
-    test_fill_buffer!(u128, write_u128);
-    test_fill_buffer!(usize, write_usize);
-
-    test_fill_buffer!(i8, write_i8);
-    test_fill_buffer!(i16, write_i16);
-    test_fill_buffer!(i32, write_i32);
-    test_fill_buffer!(i64, write_i64);
-    test_fill_buffer!(i128, write_i128);
-    test_fill_buffer!(isize, write_isize);
-}
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index a57f5067dd8..83883eeba9c 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -1,8 +1,6 @@
-use crate::sip128::SipHasher128;
 use rustc_index::bit_set::{self, BitSet};
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use smallvec::SmallVec;
-use std::fmt;
 use std::hash::{BuildHasher, Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
@@ -13,163 +11,9 @@ mod tests;
 
 pub use crate::hashes::{Hash128, Hash64};
 
-/// When hashing something that ends up affecting properties like symbol names,
-/// we want these symbol names to be calculated independently of other factors
-/// like what architecture you're compiling *from*.
-///
-/// To that end we always convert integers to little-endian format before
-/// hashing and the architecture dependent `isize` and `usize` types are
-/// extended to 64 bits if needed.
-pub struct StableHasher {
-    state: SipHasher128,
-}
-
-impl fmt::Debug for StableHasher {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.state)
-    }
-}
-
-pub trait StableHasherResult: Sized {
-    fn finish(hasher: StableHasher) -> Self;
-}
-
-impl StableHasher {
-    #[inline]
-    pub fn new() -> Self {
-        StableHasher { state: SipHasher128::new_with_keys(0, 0) }
-    }
-
-    #[inline]
-    pub fn finish<W: StableHasherResult>(self) -> W {
-        W::finish(self)
-    }
-}
-
-impl StableHasher {
-    #[inline]
-    pub fn finalize(self) -> (u64, u64) {
-        self.state.finish128()
-    }
-}
-
-impl Hasher for StableHasher {
-    fn finish(&self) -> u64 {
-        panic!("use StableHasher::finalize instead");
-    }
-
-    #[inline]
-    fn write(&mut self, bytes: &[u8]) {
-        self.state.write(bytes);
-    }
-
-    #[inline]
-    fn write_str(&mut self, s: &str) {
-        self.state.write_str(s);
-    }
-
-    #[inline]
-    fn write_length_prefix(&mut self, len: usize) {
-        // Our impl for `usize` will extend it if needed.
-        self.write_usize(len);
-    }
-
-    #[inline]
-    fn write_u8(&mut self, i: u8) {
-        self.state.write_u8(i);
-    }
-
-    #[inline]
-    fn write_u16(&mut self, i: u16) {
-        self.state.short_write(i.to_le_bytes());
-    }
-
-    #[inline]
-    fn write_u32(&mut self, i: u32) {
-        self.state.short_write(i.to_le_bytes());
-    }
-
-    #[inline]
-    fn write_u64(&mut self, i: u64) {
-        self.state.short_write(i.to_le_bytes());
-    }
-
-    #[inline]
-    fn write_u128(&mut self, i: u128) {
-        self.write_u64(i as u64);
-        self.write_u64((i >> 64) as u64);
-    }
-
-    #[inline]
-    fn write_usize(&mut self, i: usize) {
-        // Always treat usize as u64 so we get the same results on 32 and 64 bit
-        // platforms. This is important for symbol hashes when cross compiling,
-        // for example.
-        self.state.short_write((i as u64).to_le_bytes());
-    }
-
-    #[inline]
-    fn write_i8(&mut self, i: i8) {
-        self.state.write_i8(i);
-    }
-
-    #[inline]
-    fn write_i16(&mut self, i: i16) {
-        self.state.short_write((i as u16).to_le_bytes());
-    }
-
-    #[inline]
-    fn write_i32(&mut self, i: i32) {
-        self.state.short_write((i as u32).to_le_bytes());
-    }
-
-    #[inline]
-    fn write_i64(&mut self, i: i64) {
-        self.state.short_write((i as u64).to_le_bytes());
-    }
-
-    #[inline]
-    fn write_i128(&mut self, i: i128) {
-        self.state.write(&(i as u128).to_le_bytes());
-    }
-
-    #[inline]
-    fn write_isize(&mut self, i: isize) {
-        // Always treat isize as a 64-bit number so we get the same results on 32 and 64 bit
-        // platforms. This is important for symbol hashes when cross compiling,
-        // for example. Sign extending here is preferable as it means that the
-        // same negative number hashes the same on both 32 and 64 bit platforms.
-        let value = i as u64;
-
-        // Cold path
-        #[cold]
-        #[inline(never)]
-        fn hash_value(state: &mut SipHasher128, value: u64) {
-            state.write_u8(0xFF);
-            state.short_write(value.to_le_bytes());
-        }
-
-        // `isize` values often seem to have a small (positive) numeric value in practice.
-        // To exploit this, if the value is small, we will hash a smaller amount of bytes.
-        // However, we cannot just skip the leading zero bytes, as that would produce the same hash
-        // e.g. if you hash two values that have the same bit pattern when they are swapped.
-        // See https://github.com/rust-lang/rust/pull/93014 for context.
-        //
-        // Therefore, we employ the following strategy:
-        // 1) When we encounter a value that fits within a single byte (the most common case), we
-        // hash just that byte. This is the most common case that is being optimized. However, we do
-        // not do this for the value 0xFF, as that is a reserved prefix (a bit like in UTF-8).
-        // 2) When we encounter a larger value, we hash a "marker" 0xFF and then the corresponding
-        // 8 bytes. Since this prefix cannot occur when we hash a single byte, when we hash two
-        // `isize`s that fit within a different amount of bytes, they should always produce a different
-        // byte stream for the hasher.
-        if value < 0xFF {
-            self.state.write_u8(value as u8);
-        } else {
-            hash_value(&mut self.state, value);
-        }
-    }
-}
+pub use rustc_stable_hash::FromStableHash;
+pub use rustc_stable_hash::SipHasher128Hash as StableHasherHash;
+pub use rustc_stable_hash::StableSipHasher128 as StableHasher;
 
 /// Something that implements `HashStable<CTX>` can be hashed in a way that is
 /// stable across multiple compilation sessions.
diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
index c8921f6a778..aab50a13af0 100644
--- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
@@ -7,71 +7,6 @@ use super::*;
 // ways). The expected values depend on the hashing algorithm used, so they
 // need to be updated whenever StableHasher changes its hashing algorithm.
 
-#[test]
-fn test_hash_integers() {
-    // Test that integers are handled consistently across platforms.
-    let test_u8 = 0xAB_u8;
-    let test_u16 = 0xFFEE_u16;
-    let test_u32 = 0x445577AA_u32;
-    let test_u64 = 0x01234567_13243546_u64;
-    let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128;
-    let test_usize = 0xD0C0B0A0_usize;
-
-    let test_i8 = -100_i8;
-    let test_i16 = -200_i16;
-    let test_i32 = -300_i32;
-    let test_i64 = -400_i64;
-    let test_i128 = -500_i128;
-    let test_isize = -600_isize;
-
-    let mut h = StableHasher::new();
-    test_u8.hash(&mut h);
-    test_u16.hash(&mut h);
-    test_u32.hash(&mut h);
-    test_u64.hash(&mut h);
-    test_u128.hash(&mut h);
-    test_usize.hash(&mut h);
-    test_i8.hash(&mut h);
-    test_i16.hash(&mut h);
-    test_i32.hash(&mut h);
-    test_i64.hash(&mut h);
-    test_i128.hash(&mut h);
-    test_isize.hash(&mut h);
-
-    // This depends on the hashing algorithm. See note at top of file.
-    let expected = (13997337031081104755, 6178945012502239489);
-
-    assert_eq!(h.finalize(), expected);
-}
-
-#[test]
-fn test_hash_usize() {
-    // Test that usize specifically is handled consistently across platforms.
-    let test_usize = 0xABCDEF01_usize;
-
-    let mut h = StableHasher::new();
-    test_usize.hash(&mut h);
-
-    // This depends on the hashing algorithm. See note at top of file.
-    let expected = (12037165114281468837, 3094087741167521712);
-
-    assert_eq!(h.finalize(), expected);
-}
-
-#[test]
-fn test_hash_isize() {
-    // Test that isize specifically is handled consistently across platforms.
-    let test_isize = -7_isize;
-
-    let mut h = StableHasher::new();
-    test_isize.hash(&mut h);
-
-    // This depends on the hashing algorithm. See note at top of file.
-    let expected = (3979067582695659080, 2322428596355037273);
-
-    assert_eq!(h.finalize(), expected);
-}
-
 fn hash<T: HashStable<()>>(t: &T) -> Hash128 {
     let mut h = StableHasher::new();
     let ctx = &mut ();
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs
index bfcc2e603de..160af8a65d9 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs
@@ -1,5 +1,6 @@
 use std::ptr;
 
+use crate::hashes::Hash128;
 use crate::stable_hasher::{HashStable, StableHasher};
 use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag, Tag2};
 
@@ -31,14 +32,13 @@ fn stable_hash_hashes_as_tuple() {
     let hash_packed = {
         let mut hasher = StableHasher::new();
         tag_ptr(&12, Tag2::B11).hash_stable(&mut (), &mut hasher);
-
-        hasher.finalize()
+        hasher.finish::<Hash128>()
     };
 
     let hash_tupled = {
         let mut hasher = StableHasher::new();
         (&12, Tag2::B11).hash_stable(&mut (), &mut hasher);
-        hasher.finalize()
+        hasher.finish::<Hash128>()
     };
 
     assert_eq!(hash_packed, hash_tupled);
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 40e16b45115..9da4aa84db5 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -187,6 +187,7 @@ impl<'a> StripUnconfigured<'a> {
             .iter()
             .filter_map(|tree| match tree.clone() {
                 AttrTokenTree::AttrsTarget(mut target) => {
+                    // Expand any `cfg_attr` attributes.
                     target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
 
                     if self.in_cfg(&target.attrs) {
@@ -195,6 +196,8 @@ impl<'a> StripUnconfigured<'a> {
                         );
                         Some(AttrTokenTree::AttrsTarget(target))
                     } else {
+                        // Remove the target if there's a `cfg` attribute and
+                        // the condition isn't satisfied.
                         None
                     }
                 }
@@ -253,9 +256,9 @@ impl<'a> StripUnconfigured<'a> {
     /// Gives a compiler warning when the `cfg_attr` contains no attributes and
     /// is in the original source file. Gives a compiler error if the syntax of
     /// the attribute is incorrect.
-    pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
+    pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
         let Some((cfg_predicate, expanded_attrs)) =
-            rustc_parse::parse_cfg_attr(attr, &self.sess.psess)
+            rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess)
         else {
             return vec![];
         };
@@ -264,7 +267,7 @@ impl<'a> StripUnconfigured<'a> {
         if expanded_attrs.is_empty() {
             self.sess.psess.buffer_lint(
                 rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
-                attr.span,
+                cfg_attr.span,
                 ast::CRATE_NODE_ID,
                 BuiltinLintDiag::CfgAttrNoAttributes,
             );
@@ -280,20 +283,21 @@ impl<'a> StripUnconfigured<'a> {
             //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
             expanded_attrs
                 .into_iter()
-                .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item)))
+                .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(cfg_attr, item)))
                 .collect()
         } else {
-            expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect()
+            expanded_attrs
+                .into_iter()
+                .map(|item| self.expand_cfg_attr_item(cfg_attr, item))
+                .collect()
         }
     }
 
     fn expand_cfg_attr_item(
         &self,
-        attr: &Attribute,
+        cfg_attr: &Attribute,
         (item, item_span): (ast::AttrItem, Span),
     ) -> Attribute {
-        let orig_tokens = attr.get_tokens();
-
         // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
         // and producing an attribute of the form `#[attr]`. We
         // have captured tokens for `attr` itself, but we need to
@@ -302,11 +306,11 @@ impl<'a> StripUnconfigured<'a> {
 
         // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
         // for `attr` when we expand it to `#[attr]`
-        let mut orig_trees = orig_tokens.trees();
+        let mut orig_trees = cfg_attr.token_trees().into_iter();
         let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) =
             orig_trees.next().unwrap().clone()
         else {
-            panic!("Bad tokens for attribute {attr:?}");
+            panic!("Bad tokens for attribute {cfg_attr:?}");
         };
 
         // We don't really have a good span to use for the synthesized `[]`
@@ -320,12 +324,12 @@ impl<'a> StripUnconfigured<'a> {
                 .unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
                 .to_attr_token_stream(),
         );
-        let trees = if attr.style == AttrStyle::Inner {
+        let trees = if cfg_attr.style == AttrStyle::Inner {
             // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
             let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) =
                 orig_trees.next().unwrap().clone()
             else {
-                panic!("Bad tokens for attribute {attr:?}");
+                panic!("Bad tokens for attribute {cfg_attr:?}");
             };
             vec![
                 AttrTokenTree::Token(pound_token, Spacing::Joint),
@@ -340,7 +344,7 @@ impl<'a> StripUnconfigured<'a> {
             &self.sess.psess.attr_id_generator,
             item,
             tokens,
-            attr.style,
+            cfg_attr.style,
             item_span,
         );
         if attr.has_name(sym::crate_type) {
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index f082cc2b569..e671c768239 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -42,6 +42,10 @@ declare_features! (
     // feature-group-start: accepted features
     // -------------------------------------------------------------------------
 
+    // Note that the version indicates when it got *stabilized*.
+    // When moving an unstable feature here, set the version number to
+    // `CURRENT RUSTC VERSION` with ` ` replaced by `_`.
+
     /// Allows `#[target_feature(...)]` on aarch64 platforms
     (accepted, aarch64_target_feature, "1.61.0", Some(44839)),
     /// Allows using the `efiapi` ABI.
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index bf429364318..e9d3ce0a074 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -31,6 +31,10 @@ use std::num::NonZero;
 #[derive(Debug, Clone)]
 pub struct Feature {
     pub name: Symbol,
+    /// For unstable features: the version the feature was added in.
+    /// For accepted features: the version the feature got stabilized in.
+    /// For removed features we are inconsistent; sometimes this is the
+    /// version it got added, sometimes the version it got removed.
     pub since: &'static str,
     issue: Option<NonZero<u32>>,
 }
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index aea447b2aff..80a108d2fc8 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -32,6 +32,12 @@ declare_features! (
     // feature-group-start: removed features
     // -------------------------------------------------------------------------
 
+    // Note that the version indicates when it got *removed*.
+    // When moving an unstable feature here, set the version number to
+    // `CURRENT RUSTC VERSION` with ` ` replaced by `_`.
+    // (But not all features below do this properly; many indicate the
+    // version they got originally added in.)
+
     /// Allows using the `amdgpu-kernel` ABI.
     (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None),
     (removed, advanced_slice_patterns, "1.0.0", Some(62254),
@@ -215,6 +221,9 @@ declare_features! (
     /// Permits specifying whether a function should permit unwinding or abort on unwind.
     (removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead")),
     (removed, visible_private_types, "1.0.0", None, None),
+    /// Allows `extern "wasm" fn`
+    (removed, wasm_abi, "CURRENT_RUSTC_VERSION", Some(83788),
+     Some("non-standard wasm ABI is no longer supported")),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index c05cac155b7..1db3774222a 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -248,6 +248,8 @@ declare_features! (
     (unstable, auto_traits, "1.50.0", Some(13231)),
     /// Allows using `box` in patterns (RFC 469).
     (unstable, box_patterns, "1.0.0", Some(29641)),
+    /// Allows builtin # foo() syntax
+    (internal, builtin_syntax, "1.71.0", Some(110680)),
     /// Allows `#[doc(notable_trait)]`.
     /// Renamed from `doc_spotlight`.
     (unstable, doc_notable_trait, "1.52.0", Some(45040)),
@@ -361,8 +363,6 @@ declare_features! (
     (unstable, async_fn_track_caller, "1.73.0", Some(110011)),
     /// Allows `for await` loops.
     (unstable, async_for_loop, "1.77.0", Some(118898)),
-    /// Allows builtin # foo() syntax
-    (unstable, builtin_syntax, "1.71.0", Some(110680)),
     /// Allows using C-variadics.
     (unstable, c_variadic, "1.34.0", Some(44930)),
     /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
@@ -621,8 +621,6 @@ declare_features! (
     (unstable, try_blocks, "1.29.0", Some(31436)),
     /// Allows `impl Trait` to be used inside type aliases (RFC 2515).
     (unstable, type_alias_impl_trait, "1.38.0", Some(63063)),
-    /// Allows the use of type ascription in expressions.
-    (unstable, type_ascription, "1.6.0", Some(23416)),
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
     (unstable, type_changing_struct_update, "1.58.0", Some(86555)),
@@ -640,8 +638,10 @@ declare_features! (
     (unstable, unsized_tuple_coercion, "1.20.0", Some(42877)),
     /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
     (unstable, used_with_arg, "1.60.0", Some(93798)),
-    /// Allows `extern "wasm" fn`
-    (unstable, wasm_abi, "1.53.0", Some(83788)),
+    /// Allows use of x86 `AMX` target-feature attributes and intrinsics
+    (unstable, x86_amx_intrinsics, "CURRENT_RUSTC_VERSION", Some(126622)),
+    /// Allows use of the `xop` target-feature
+    (unstable, xop_target_feature, "CURRENT_RUSTC_VERSION", Some(127208)),
     /// Allows `do yeet` expressions
     (unstable, yeet_expr, "1.62.0", Some(96373)),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index d57fad6ba4c..3bd7b300758 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2708,6 +2708,13 @@ impl PreciseCapturingArg<'_> {
             PreciseCapturingArg::Param(param) => param.hir_id,
         }
     }
+
+    pub fn name(self) -> Symbol {
+        match self {
+            PreciseCapturingArg::Lifetime(lt) => lt.ident.name,
+            PreciseCapturingArg::Param(param) => param.ident.name,
+        }
+    }
 }
 
 /// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param
@@ -3211,10 +3218,10 @@ impl<'hir> Item<'hir> {
             ItemKind::Static(ty, mutbl, body), (ty, *mutbl, *body);
 
         expect_const, (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
-            ItemKind::Const(ty, gen, body), (ty, gen, *body);
+            ItemKind::Const(ty, generics, body), (ty, generics, *body);
 
         expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId),
-            ItemKind::Fn(sig, gen, body), (sig, gen, *body);
+            ItemKind::Fn(sig, generics, body), (sig, generics, *body);
 
         expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk);
 
@@ -3226,25 +3233,25 @@ impl<'hir> Item<'hir> {
         expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm;
 
         expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
-            ItemKind::TyAlias(ty, gen), (ty, gen);
+            ItemKind::TyAlias(ty, generics), (ty, generics);
 
         expect_opaque_ty, &OpaqueTy<'hir>, ItemKind::OpaqueTy(ty), ty;
 
-        expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, gen), (def, gen);
+        expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics);
 
         expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>),
-            ItemKind::Struct(data, gen), (data, gen);
+            ItemKind::Struct(data, generics), (data, generics);
 
         expect_union, (&VariantData<'hir>, &'hir Generics<'hir>),
-            ItemKind::Union(data, gen), (data, gen);
+            ItemKind::Union(data, generics), (data, generics);
 
         expect_trait,
             (IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
-            ItemKind::Trait(is_auto, safety, gen, bounds, items),
-            (*is_auto, *safety, gen, bounds, items);
+            ItemKind::Trait(is_auto, safety, generics, bounds, items),
+            (*is_auto, *safety, generics, bounds, items);
 
         expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>),
-            ItemKind::TraitAlias(gen, bounds), (gen, bounds);
+            ItemKind::TraitAlias(generics, bounds), (generics, bounds);
 
         expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp;
     }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 0acc119115a..e0aad299163 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -35,7 +35,6 @@ use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::FieldIdx;
 use rustc_target::spec::abi;
 use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -85,7 +84,6 @@ pub fn provide(providers: &mut Providers) {
         coroutine_kind,
         coroutine_for_closure,
         is_type_alias_impl_trait,
-        find_field,
         ..*providers
     };
 }
@@ -914,23 +912,6 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
     }
 }
 
-fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
-    let adt = tcx.adt_def(def_id);
-    if adt.is_enum() {
-        return None;
-    }
-
-    adt.non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
-        if field.is_unnamed() {
-            let field_ty = tcx.type_of(field.did).instantiate_identity();
-            let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
-            tcx.find_field((adt_def.did(), ident)).map(|_| idx)
-        } else {
-            (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
-        }
-    })
-}
-
 #[derive(Clone, Copy)]
 struct NestedSpan {
     span: Span,
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index f057dbc013f..035a3429ed7 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -59,6 +59,8 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
 
+use smallvec::SmallVec;
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_expr_has_type_or_error(
         &self,
@@ -2318,6 +2320,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         display
     }
 
+    /// Find the position of a field named `ident` in `base_def`, accounting for unnammed fields.
+    /// Return whether such a field has been found. The path to it is stored in `nested_fields`.
+    /// `ident` must have been adjusted beforehand.
+    fn find_adt_field(
+        &self,
+        base_def: ty::AdtDef<'tcx>,
+        ident: Ident,
+        nested_fields: &mut SmallVec<[(FieldIdx, &'tcx ty::FieldDef); 1]>,
+    ) -> bool {
+        // No way to find a field in an enum.
+        if base_def.is_enum() {
+            return false;
+        }
+
+        for (field_idx, field) in base_def.non_enum_variant().fields.iter_enumerated() {
+            if field.is_unnamed() {
+                // We have an unnamed field, recurse into the nested ADT to find `ident`.
+                // If we find it there, return immediately, and `nested_fields` will contain the
+                // correct path.
+                nested_fields.push((field_idx, field));
+
+                let field_ty = self.tcx.type_of(field.did).instantiate_identity();
+                let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
+                if self.find_adt_field(adt_def, ident, &mut *nested_fields) {
+                    return true;
+                }
+
+                nested_fields.pop();
+            } else if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
+                // We found the field we wanted.
+                nested_fields.push((field_idx, field));
+                return true;
+            }
+        }
+
+        false
+    }
+
     // Check field access expressions
     fn check_field(
         &self,
@@ -2339,44 +2379,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
                     let (ident, def_scope) =
                         self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
-                    let mut adt_def = *base_def;
-                    let mut last_ty = None;
-                    let mut nested_fields = Vec::new();
-                    let mut index = None;
 
                     // we don't care to report errors for a struct if the struct itself is tainted
-                    if let Err(guar) = adt_def.non_enum_variant().has_errors() {
+                    if let Err(guar) = base_def.non_enum_variant().has_errors() {
                         return Ty::new_error(self.tcx(), guar);
                     }
-                    while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) {
-                        let &mut first_idx = index.get_or_insert(idx);
-                        let field = &adt_def.non_enum_variant().fields[idx];
-                        let field_ty = self.field_ty(expr.span, field, args);
-                        if let Some(ty) = last_ty {
-                            nested_fields.push((ty, idx));
-                        }
-                        if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
-                            // Save the index of all fields regardless of their visibility in case
-                            // of error recovery.
-                            self.write_field_index(expr.hir_id, first_idx, nested_fields);
-                            let adjustments = self.adjust_steps(&autoderef);
-                            if field.vis.is_accessible_from(def_scope, self.tcx) {
-                                self.apply_adjustments(base, adjustments);
-                                self.register_predicates(autoderef.into_obligations());
 
-                                self.tcx.check_stability(
-                                    field.did,
-                                    Some(expr.hir_id),
-                                    expr.span,
-                                    None,
-                                );
-                                return field_ty;
-                            }
-                            private_candidate = Some((adjustments, base_def.did()));
-                            break;
+                    let mut field_path = SmallVec::new();
+                    if self.find_adt_field(*base_def, ident, &mut field_path) {
+                        let (first_idx, _) = field_path[0];
+                        let (_, last_field) = field_path.last().unwrap();
+
+                        // Save the index of all fields regardless of their visibility in case
+                        // of error recovery.
+                        let nested_fields = field_path[..]
+                            .array_windows()
+                            .map(|[(_, outer), (inner_idx, _)]| {
+                                let outer_ty = self.field_ty(expr.span, outer, args);
+                                (outer_ty, *inner_idx)
+                            })
+                            .collect();
+                        self.write_field_index(expr.hir_id, first_idx, nested_fields);
+
+                        let adjustments = self.adjust_steps(&autoderef);
+                        if last_field.vis.is_accessible_from(def_scope, self.tcx) {
+                            self.apply_adjustments(base, adjustments);
+                            self.register_predicates(autoderef.into_obligations());
+
+                            self.tcx.check_stability(
+                                last_field.did,
+                                Some(expr.hir_id),
+                                expr.span,
+                                None,
+                            );
+                            return self.field_ty(expr.span, last_field, args);
                         }
-                        last_ty = Some(field_ty);
-                        adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
+
+                        // The field is not accessible, fall through to error reporting.
+                        private_candidate = Some((adjustments, base_def.did()));
                     }
                 }
                 ty::Tuple(tys) => {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index ab0f356ce91..9fbb01216bb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -948,6 +948,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 &mut err,
             );
 
+            self.suggest_deref_unwrap_or(
+                &mut err,
+                error_span,
+                callee_ty,
+                call_ident,
+                expected_ty,
+                provided_ty,
+                provided_args[*provided_idx],
+                is_method,
+            );
+
             // Call out where the function is defined
             self.label_fn_like(
                 &mut err,
@@ -2554,7 +2565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .and_then(|node| node.generics())
                         .into_iter()
                         .flat_map(|generics| generics.params)
-                        .find(|gen| &gen.def_id.to_def_id() == res_def_id)
+                        .find(|param| &param.def_id.to_def_id() == res_def_id)
                 } else {
                     None
                 }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 5f897c74482..b3b4c5a56fb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -466,21 +466,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     borrow_removal_span,
                 });
                 return true;
-            } else if let Some((deref_ty, _)) =
-                self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1)
-                && self.can_eq(self.param_env, deref_ty, peeled)
-                && error_tys_equate_as_ref
-            {
-                let sugg = prefix_wrap(".as_deref()");
-                err.subdiagnostic(errors::SuggestConvertViaMethod {
-                    span: expr.span.shrink_to_hi(),
-                    sugg,
-                    expected,
-                    found,
-                    borrow_removal_span,
-                });
-                return true;
-            } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind()
+            } else if let ty::Ref(_, peeled_found_ty, _) = found_ty_inner.kind()
+                && let ty::Adt(adt, _) = peeled_found_ty.peel_refs().kind()
                 && self.tcx.is_lang_item(adt.did(), LangItem::String)
                 && peeled.is_str()
                 // `Result::map`, conversely, does not take ref of the error type.
@@ -496,12 +483,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     Applicability::MachineApplicable,
                 );
                 return true;
+            } else {
+                if !error_tys_equate_as_ref {
+                    return false;
+                }
+                let mut steps = self.autoderef(expr.span, found_ty_inner).silence_errors();
+                if let Some((deref_ty, _)) = steps.nth(1)
+                    && self.can_eq(self.param_env, deref_ty, peeled)
+                {
+                    let sugg = prefix_wrap(".as_deref()");
+                    err.subdiagnostic(errors::SuggestConvertViaMethod {
+                        span: expr.span.shrink_to_hi(),
+                        sugg,
+                        expected,
+                        found,
+                        borrow_removal_span,
+                    });
+                    return true;
+                }
+                for (deref_ty, n_step) in steps {
+                    if self.can_eq(self.param_env, deref_ty, peeled) {
+                        let explicit_deref = "*".repeat(n_step);
+                        let sugg = prefix_wrap(&format!(".map(|v| &{explicit_deref}v)"));
+                        err.subdiagnostic(errors::SuggestConvertViaMethod {
+                            span: expr.span.shrink_to_hi(),
+                            sugg,
+                            expected,
+                            found,
+                            borrow_removal_span,
+                        });
+                        return true;
+                    }
+                }
             }
         }
 
         false
     }
 
+    /// If `ty` is `Option<T>`, returns `T, T, None`.
+    /// If `ty` is `Result<T, E>`, returns `T, T, Some(E, E)`.
+    /// Otherwise, returns `None`.
     fn deconstruct_option_or_result(
         &self,
         found_ty: Ty<'tcx>,
@@ -1407,6 +1429,74 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         true
     }
 
+    // Suggest to change `Option<&Vec<T>>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`.
+    #[instrument(level = "trace", skip(self, err, provided_expr))]
+    pub(crate) fn suggest_deref_unwrap_or(
+        &self,
+        err: &mut Diag<'_>,
+        error_span: Span,
+        callee_ty: Option<Ty<'tcx>>,
+        call_ident: Option<Ident>,
+        expected_ty: Ty<'tcx>,
+        provided_ty: Ty<'tcx>,
+        provided_expr: &Expr<'tcx>,
+        is_method: bool,
+    ) {
+        if !is_method {
+            return;
+        }
+        let Some(callee_ty) = callee_ty else {
+            return;
+        };
+        let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else {
+            return;
+        };
+        let adt_name = if self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) {
+            "Option"
+        } else if self.tcx.is_diagnostic_item(sym::Result, callee_adt.did()) {
+            "Result"
+        } else {
+            return;
+        };
+
+        let Some(call_ident) = call_ident else {
+            return;
+        };
+        if call_ident.name != sym::unwrap_or {
+            return;
+        }
+
+        let ty::Ref(_, peeled, _mutability) = provided_ty.kind() else {
+            return;
+        };
+
+        // NOTE: Can we reuse `suggest_deref_or_ref`?
+
+        // Create an dummy type `&[_]` so that both &[] and `&Vec<T>` can coerce to it.
+        let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind()
+            && let ty::Infer(_) = elem_ty.kind()
+            && size.try_eval_target_usize(self.tcx, self.param_env) == Some(0)
+        {
+            let slice = Ty::new_slice(self.tcx, *elem_ty);
+            Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice)
+        } else {
+            provided_ty
+        };
+
+        if !self.can_coerce(expected_ty, dummy_ty) {
+            return;
+        }
+        let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`");
+        err.multipart_suggestion_verbose(
+            msg,
+            vec![
+                (call_ident.span, "map_or".to_owned()),
+                (provided_expr.span.shrink_to_hi(), ", |v| v".to_owned()),
+            ],
+            Applicability::MachineApplicable,
+        );
+    }
+
     /// Suggest wrapping the block in square brackets instead of curly braces
     /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
     pub(crate) fn suggest_block_to_brackets(
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index a87ee7b4554..bdbdcee6446 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -1,6 +1,7 @@
 // tidy-alphabetical-start
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index fbe8d31370c..7a5e7159920 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -221,6 +221,10 @@ infer_opaque_hidden_type =
 
 infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
 infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
+
+infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it
+infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}`
+
 infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
 infer_prlf_defined_without_sub = the lifetime defined here...
 infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index a801001eaf9..ce1b0f86d03 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1581,3 +1581,32 @@ pub enum ObligationCauseFailureCode {
         subdiags: Vec<TypeErrorAdditionalDiags>,
     },
 }
+
+#[derive(Subdiagnostic)]
+pub enum AddPreciseCapturing {
+    #[suggestion(
+        infer_precise_capturing_new,
+        style = "verbose",
+        code = " + use<{concatenated_bounds}>",
+        applicability = "machine-applicable"
+    )]
+    New {
+        #[primary_span]
+        span: Span,
+        new_lifetime: Symbol,
+        concatenated_bounds: String,
+    },
+    #[suggestion(
+        infer_precise_capturing_existing,
+        style = "verbose",
+        code = "{pre}{new_lifetime}{post}",
+        applicability = "machine-applicable"
+    )]
+    Existing {
+        #[primary_span]
+        span: Span,
+        new_lifetime: Symbol,
+        pre: &'static str,
+        post: &'static str,
+    },
+}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/region.rs b/compiler/rustc_infer/src/infer/error_reporting/region.rs
index 5a465f46e47..191cb23184d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/region.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/region.rs
@@ -1,5 +1,6 @@
 use std::iter;
 
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
     struct_span_code_err, Applicability, Diag, Subdiagnostic, E0309, E0310, E0311, E0495,
 };
@@ -12,7 +13,7 @@ use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _};
 use rustc_span::symbol::kw;
-use rustc_span::{ErrorGuaranteed, Span};
+use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol};
 use rustc_type_ir::Upcast as _;
 
 use super::nice_region_error::find_anon_type;
@@ -1201,17 +1202,21 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
                 "",
             );
             if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
-                let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
-                nice_region_error::suggest_new_region_bound(
-                    tcx,
-                    &mut err,
-                    fn_returns,
-                    hidden_region.to_string(),
-                    None,
-                    format!("captures `{hidden_region}`"),
-                    None,
-                    Some(reg_info.def_id),
-                )
+                if infcx.tcx.features().precise_capturing {
+                    suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err);
+                } else {
+                    let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
+                    nice_region_error::suggest_new_region_bound(
+                        tcx,
+                        &mut err,
+                        fn_returns,
+                        hidden_region.to_string(),
+                        None,
+                        format!("captures `{hidden_region}`"),
+                        None,
+                        Some(reg_info.def_id),
+                    )
+                }
             }
         }
         ty::RePlaceholder(_) => {
@@ -1257,3 +1262,95 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
 
     err
 }
+
+fn suggest_precise_capturing<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    opaque_def_id: LocalDefId,
+    captured_lifetime: ty::Region<'tcx>,
+    diag: &mut Diag<'_>,
+) {
+    let hir::OpaqueTy { bounds, .. } =
+        tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+
+    let new_lifetime = Symbol::intern(&captured_lifetime.to_string());
+
+    if let Some((args, span)) = bounds.iter().find_map(|bound| match bound {
+        hir::GenericBound::Use(args, span) => Some((args, span)),
+        _ => None,
+    }) {
+        let last_lifetime_span = args.iter().rev().find_map(|arg| match arg {
+            hir::PreciseCapturingArg::Lifetime(lt) => Some(lt.ident.span),
+            _ => None,
+        });
+
+        let first_param_span = args.iter().find_map(|arg| match arg {
+            hir::PreciseCapturingArg::Param(p) => Some(p.ident.span),
+            _ => None,
+        });
+
+        let (span, pre, post) = if let Some(last_lifetime_span) = last_lifetime_span {
+            (last_lifetime_span.shrink_to_hi(), ", ", "")
+        } else if let Some(first_param_span) = first_param_span {
+            (first_param_span.shrink_to_lo(), "", ", ")
+        } else {
+            // If we have no args, then have `use<>` and need to fall back to using
+            // span math. This sucks, but should be reliable due to the construction
+            // of the `use<>` span.
+            (span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), "", "")
+        };
+
+        diag.subdiagnostic(errors::AddPreciseCapturing::Existing { span, new_lifetime, pre, post });
+    } else {
+        let mut captured_lifetimes = FxIndexSet::default();
+        let mut captured_non_lifetimes = FxIndexSet::default();
+
+        let variances = tcx.variances_of(opaque_def_id);
+        let mut generics = tcx.generics_of(opaque_def_id);
+        loop {
+            for param in &generics.own_params {
+                if variances[param.index as usize] == ty::Bivariant {
+                    continue;
+                }
+
+                match param.kind {
+                    ty::GenericParamDefKind::Lifetime => {
+                        captured_lifetimes.insert(param.name);
+                    }
+                    ty::GenericParamDefKind::Type { synthetic: true, .. } => {
+                        // FIXME: We can't provide a good suggestion for
+                        // `use<...>` if we have an APIT. Bail for now.
+                        return;
+                    }
+                    ty::GenericParamDefKind::Type { .. }
+                    | ty::GenericParamDefKind::Const { .. } => {
+                        captured_non_lifetimes.insert(param.name);
+                    }
+                }
+            }
+
+            if let Some(parent) = generics.parent {
+                generics = tcx.generics_of(parent);
+            } else {
+                break;
+            }
+        }
+
+        if !captured_lifetimes.insert(new_lifetime) {
+            // Uh, strange. This lifetime appears to already be captured...
+            return;
+        }
+
+        let concatenated_bounds = captured_lifetimes
+            .into_iter()
+            .chain(captured_non_lifetimes)
+            .map(|sym| sym.to_string())
+            .collect::<Vec<_>>()
+            .join(", ");
+
+        diag.subdiagnostic(errors::AddPreciseCapturing::New {
+            span: tcx.def_span(opaque_def_id).shrink_to_hi(),
+            new_lifetime,
+            concatenated_bounds,
+        });
+    }
+}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index e2ba75dfd19..7d7a6a08bee 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -691,6 +691,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(dump_mir, Some(String::from("abc")));
     untracked!(dump_mir_dataflow, true);
     untracked!(dump_mir_dir, String::from("abc"));
+    untracked!(dump_mir_exclude_alloc_bytes, true);
     untracked!(dump_mir_exclude_pass_number, true);
     untracked!(dump_mir_graphviz, true);
     untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into())));
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 4f2d59b4c66..de04d882f51 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -52,10 +52,6 @@ lint_builtin_allow_internal_unsafe =
 lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition
     .suggestion = try naming the parameter or explicitly ignoring it
 
-lint_builtin_asm_labels = avoid using named labels in inline assembly
-    .help = only local labels of the form `<number>:` should be used in inline asm
-    .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
-
 lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature
     .previous_decl_label = `{$orig}` previously declared here
     .mismatch_label = this signature doesn't match the previous declaration
@@ -163,6 +159,8 @@ lint_builtin_unreachable_pub = unreachable `pub` {$what}
 
 lint_builtin_unsafe_block = usage of an `unsafe` block
 
+lint_builtin_unsafe_extern_block = usage of an `unsafe extern` block
+
 lint_builtin_unsafe_impl = implementation of an `unsafe` trait
 
 lint_builtin_unsafe_trait = declaration of an `unsafe` trait
@@ -403,6 +401,19 @@ lint_incomplete_include =
 
 lint_inner_macro_attribute_unstable = inner macro attributes are unstable
 
+lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly
+    .label = use a different label that doesn't start with `0` or `1`
+    .note = an LLVM bug makes these labels ambiguous with a binary literal number
+    .note = see <https://bugs.llvm.org/show_bug.cgi?id=36144> for more information
+
+lint_invalid_asm_label_format_arg = avoid using named labels in inline assembly
+    .help = only local labels of the form `<number>:` should be used in inline asm
+    .note1 = format arguments may expand to a non-numeric value
+    .note2 = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+lint_invalid_asm_label_named = avoid using named labels in inline assembly
+    .help = only local labels of the form `<number>:` should be used in inline asm
+    .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro
 lint_invalid_crate_type_value = invalid `crate_type` value
     .suggestion = did you mean
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 79c8046f9b7..485c214ac9d 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -30,13 +30,13 @@ use crate::{
         BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
         BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
         BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
-        BuiltinMutablesTransmutes, BuiltinNamedAsmLabel, BuiltinNoMangleGeneric,
-        BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds,
-        BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion,
-        BuiltinTypeAliasWhereClause, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
+        BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
+        BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
+        BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
+        BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
         BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
         BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
-        BuiltinWhileTrue, SuggestChangingAssocTypes,
+        BuiltinWhileTrue, InvalidAsmLabel, SuggestChangingAssocTypes,
     },
     EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
 };
@@ -45,7 +45,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
-use rustc_errors::{Applicability, LintDiagnostic, MultiSpan};
+use rustc_errors::{Applicability, LintDiagnostic};
 use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -69,7 +69,6 @@ use rustc_target::abi::Abi;
 use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy};
-use tracing::debug;
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
@@ -326,6 +325,12 @@ impl EarlyLintPass for UnsafeCode {
                 self.report_unsafe(cx, it.span, BuiltinUnsafe::GlobalAsm);
             }
 
+            ast::ItemKind::ForeignMod(ForeignMod { safety, .. }) => {
+                if let Safety::Unsafe(_) = safety {
+                    self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeExternBlock);
+                }
+            }
+
             _ => {}
         }
     }
@@ -2728,10 +2733,52 @@ declare_lint! {
     "named labels in inline assembly",
 }
 
-declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
+declare_lint! {
+    /// The `binary_asm_labels` lint detects the use of numeric labels containing only binary
+    /// digits in the inline `asm!` macro.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![feature(asm_experimental_arch)]
+    /// use std::arch::asm;
+    ///
+    /// fn main() {
+    ///     unsafe {
+    ///         asm!("0: jmp 0b");
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A [LLVM bug] causes this code to fail to compile because it interprets the `0b` as a binary
+    /// literal instead of a reference to the previous local label `0`. Note that even though the
+    /// bug is marked as fixed, it only fixes a specific usage of intel syntax within standalone
+    /// files, not inline assembly. To work around this bug, don't use labels that could be
+    /// confused with a binary literal.
+    ///
+    /// See the explanation in [Rust By Example] for more details.
+    ///
+    /// [LLVM bug]: https://bugs.llvm.org/show_bug.cgi?id=36144
+    /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
+    pub BINARY_ASM_LABELS,
+    Deny,
+    "labels in inline assembly containing only 0 or 1 digits",
+}
+
+declare_lint_pass!(AsmLabels => [NAMED_ASM_LABELS, BINARY_ASM_LABELS]);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum AsmLabelKind {
+    Named,
+    FormatArg,
+    Binary,
+}
 
-impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
-    #[allow(rustc::diagnostic_outside_of_impl)]
+impl<'tcx> LateLintPass<'tcx> for AsmLabels {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::Expr {
             kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }),
@@ -2759,7 +2806,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
                     None
                 };
 
-                let mut found_labels = Vec::new();
+                // diagnostics are emitted per-template, so this is created here as opposed to the outer loop
+                let mut spans = Vec::new();
 
                 // A semicolon might not actually be specified as a separator for all targets, but
                 // it seems like LLVM accepts it always.
@@ -2782,16 +2830,21 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
 
                         // Whether a { bracket has been seen and its } hasn't been found yet.
                         let mut in_bracket = false;
+                        let mut label_kind = AsmLabelKind::Named;
 
-                        // A label starts with an ASCII alphabetic character or . or _
                         // A label can also start with a format arg, if it's not a raw asm block.
                         if !raw && start == '{' {
                             in_bracket = true;
+                            label_kind = AsmLabelKind::FormatArg;
+                        } else if matches!(start, '0' | '1') {
+                            // Binary labels have only the characters `0` or `1`.
+                            label_kind = AsmLabelKind::Binary;
                         } else if !(start.is_ascii_alphabetic() || matches!(start, '.' | '_')) {
+                            // Named labels start with ASCII letters, `.` or `_`.
+                            // anything else is not a label
                             break 'label_loop;
                         }
 
-                        // Labels continue with ASCII alphanumeric characters, _, or $
                         for c in chars {
                             // Inside a template format arg, any character is permitted for the
                             // puproses of label detection because we assume that it can be
@@ -2812,8 +2865,18 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
                             } else if !raw && c == '{' {
                                 // Start of a format arg.
                                 in_bracket = true;
+                                label_kind = AsmLabelKind::FormatArg;
                             } else {
-                                if !(c.is_ascii_alphanumeric() || matches!(c, '_' | '$')) {
+                                let can_continue = match label_kind {
+                                    // Format arg labels are considered to be named labels for the purposes
+                                    // of continuing outside of their {} pair.
+                                    AsmLabelKind::Named | AsmLabelKind::FormatArg => {
+                                        c.is_ascii_alphanumeric() || matches!(c, '_' | '$')
+                                    }
+                                    AsmLabelKind::Binary => matches!(c, '0' | '1'),
+                                };
+
+                                if !can_continue {
                                     // The potential label had an invalid character inside it, it
                                     // cannot be a label.
                                     break 'label_loop;
@@ -2821,25 +2884,41 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
                             }
                         }
 
-                        // If all characters passed the label checks, this is likely a label.
-                        found_labels.push(possible_label);
+                        // If all characters passed the label checks, this is a label.
+                        spans.push((find_label_span(possible_label), label_kind));
                         start_idx = idx + 1;
                     }
                 }
 
-                debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels);
-
-                if found_labels.len() > 0 {
-                    let spans = found_labels
-                        .into_iter()
-                        .filter_map(|label| find_label_span(label))
-                        .collect::<Vec<Span>>();
-                    // If there were labels but we couldn't find a span, combine the warnings and
-                    // use the template span.
-                    let target_spans: MultiSpan =
-                        if spans.len() > 0 { spans.into() } else { (*template_span).into() };
-
-                    cx.emit_span_lint(NAMED_ASM_LABELS, target_spans, BuiltinNamedAsmLabel);
+                for (span, label_kind) in spans {
+                    let missing_precise_span = span.is_none();
+                    let span = span.unwrap_or(*template_span);
+                    match label_kind {
+                        AsmLabelKind::Named => {
+                            cx.emit_span_lint(
+                                NAMED_ASM_LABELS,
+                                span,
+                                InvalidAsmLabel::Named { missing_precise_span },
+                            );
+                        }
+                        AsmLabelKind::FormatArg => {
+                            cx.emit_span_lint(
+                                NAMED_ASM_LABELS,
+                                span,
+                                InvalidAsmLabel::FormatArg { missing_precise_span },
+                            );
+                        }
+                        AsmLabelKind::Binary => {
+                            // the binary asm issue only occurs when using intel syntax
+                            if !options.contains(InlineAsmOptions::ATT_SYNTAX) {
+                                cx.emit_span_lint(
+                                    BINARY_ASM_LABELS,
+                                    span,
+                                    InvalidAsmLabel::Binary { missing_precise_span, span },
+                                )
+                            }
+                        }
+                    };
                 }
             }
         }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index b6927cf60b6..8be8996e4c8 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -225,7 +225,7 @@ late_lint_methods!(
             NoopMethodCall: NoopMethodCall,
             EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
             InvalidAtomicOrdering: InvalidAtomicOrdering,
-            NamedAsmLabels: NamedAsmLabels,
+            AsmLabels: AsmLabels,
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
             MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
             MapUnitFn: MapUnitFn,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 54c73710eca..308bb73f4ce 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -81,6 +81,8 @@ pub enum BuiltinUnsafe {
     AllowInternalUnsafe,
     #[diag(lint_builtin_unsafe_block)]
     UnsafeBlock,
+    #[diag(lint_builtin_unsafe_extern_block)]
+    UnsafeExternBlock,
     #[diag(lint_builtin_unsafe_trait)]
     UnsafeTrait,
     #[diag(lint_builtin_unsafe_impl)]
@@ -2047,10 +2049,32 @@ pub struct UnitBindingsDiag {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_builtin_asm_labels)]
-#[help]
-#[note]
-pub struct BuiltinNamedAsmLabel;
+pub enum InvalidAsmLabel {
+    #[diag(lint_invalid_asm_label_named)]
+    #[help]
+    #[note]
+    Named {
+        #[note(lint_invalid_asm_label_no_span)]
+        missing_precise_span: bool,
+    },
+    #[diag(lint_invalid_asm_label_format_arg)]
+    #[help]
+    #[note(lint_note1)]
+    #[note(lint_note2)]
+    FormatArg {
+        #[note(lint_invalid_asm_label_no_span)]
+        missing_precise_span: bool,
+    },
+    #[diag(lint_invalid_asm_label_binary)]
+    #[note]
+    Binary {
+        #[note(lint_invalid_asm_label_no_span)]
+        missing_precise_span: bool,
+        // hack to get a label on the whole span, must match the emitted span
+        #[label]
+        span: Span,
+    },
+}
 
 #[derive(Subdiagnostic)]
 pub enum UnexpectedCfgCargoHelp {
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 5ee73dbfdc6..fdb71ad41a7 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -5,8 +5,7 @@ use rustc_middle::ty::print::{PrintTraitPredicateExt as _, TraitPredPrintModifie
 use rustc_middle::ty::{self, fold::BottomUpFolder, Ty, TypeFoldable};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::{symbol::kw, Span};
-use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{self, ObligationCtxt};
 
 use crate::{LateContext, LateLintPass, LintContext};
 
@@ -130,24 +129,26 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
                     .iter_instantiated_copied(cx.tcx, proj.projection_term.args)
                 {
                     let assoc_pred = assoc_pred.fold_with(proj_replacer);
-                    let Ok(assoc_pred) = traits::fully_normalize(
-                        infcx,
+
+                    let ocx = ObligationCtxt::new(infcx);
+                    let assoc_pred =
+                        ocx.normalize(&traits::ObligationCause::dummy(), cx.param_env, assoc_pred);
+                    if !ocx.select_all_or_error().is_empty() {
+                        // Can't normalize for some reason...?
+                        continue;
+                    }
+
+                    ocx.register_obligation(traits::Obligation::new(
+                        cx.tcx,
                         traits::ObligationCause::dummy(),
                         cx.param_env,
                         assoc_pred,
-                    ) else {
-                        continue;
-                    };
+                    ));
 
                     // If that predicate doesn't hold modulo regions (but passed during type-check),
                     // then we must've taken advantage of the hack in `project_and_unify_types` where
                     // we replace opaques with inference vars. Emit a warning!
-                    if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
-                        cx.tcx,
-                        traits::ObligationCause::dummy(),
-                        cx.param_env,
-                        assoc_pred,
-                    )) {
+                    if !ocx.select_all_or_error().is_empty() {
                         // If it's a trait bound and an opaque that doesn't satisfy it,
                         // then we can emit a suggestion to add the bound.
                         let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 3aa852c8304..4c1f78e6bee 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -197,9 +197,8 @@ fn main() {
         cfg.define("LLVM_RUSTLLVM", None);
     }
 
-    if tracked_env_var_os("LLVM_NDEBUG").is_some() {
+    if tracked_env_var_os("LLVM_ASSERTIONS").is_none() {
         cfg.define("NDEBUG", None);
-        cfg.debug(false);
     }
 
     rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper"));
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index b6790b7df50..14757b27a37 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1137,20 +1137,15 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder,
       Builder->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count)).get());
 }
 
-extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd(
+extern "C" void LLVMRustDIBuilderInsertDeclareAtEnd(
     LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
     uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
     LLVMBasicBlockRef InsertAtEnd) {
-  auto Result = Builder->insertDeclare(
-      unwrap(V), unwrap<DILocalVariable>(VarInfo),
-      Builder->createExpression(
-          llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
-      DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd));
-#if LLVM_VERSION_GE(19, 0)
-  return wrap(Result.get<llvm::Instruction *>());
-#else
-  return wrap(Result);
-#endif
+  Builder->insertDeclare(unwrap(V), unwrap<DILocalVariable>(VarInfo),
+                         Builder->createExpression(
+                             llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
+                         DebugLoc(cast<MDNode>(unwrap(DL))),
+                         unwrap(InsertAtEnd));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index a3abbdcf18c..2743660ab89 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -71,6 +71,8 @@ impl<'a> DiagnosticDerive<'a> {
         });
 
         // A lifetime of `'a` causes conflicts, but `_sess` is fine.
+        // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
+        #[allow(keyword_idents_2024)]
         let mut imp = structure.gen_impl(quote! {
             gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self
                 where G: rustc_errors::EmissionGuarantee
@@ -148,6 +150,8 @@ impl<'a> LintDiagnosticDerive<'a> {
             }
         });
 
+        // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
+        #[allow(keyword_idents_2024)]
         let mut imp = structure.gen_impl(quote! {
             gen impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for @Self {
                 #[track_caller]
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 46bd80c2df6..f93d89d6c0f 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -269,6 +269,7 @@ impl DiagnosticDeriveVariantBuilder {
         let field_binding = &binding_info.binding;
 
         let inner_ty = FieldInnerTy::from_type(&field.ty);
+        let mut seen_label = false;
 
         field
             .attrs
@@ -280,6 +281,14 @@ impl DiagnosticDeriveVariantBuilder {
                 }
 
                 let name = attr.path().segments.last().unwrap().ident.to_string();
+
+                if name == "primary_span" && seen_label {
+                    span_err(attr.span().unwrap(), format!("`#[primary_span]` must be placed before labels, since it overwrites the span of the diagnostic")).emit();
+                }
+                if name == "label" {
+                    seen_label = true;
+                }
+
                 let needs_clone =
                     name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
                 let (binding, needs_destructure) = if needs_clone {
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 69014f39925..7f090f5ebc1 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -86,6 +86,9 @@ impl SubdiagnosticDerive {
 
         let diag = &self.diag;
         let f = &self.f;
+
+        // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
+        #[allow(keyword_idents_2024)]
         let ret = structure.gen_impl(quote! {
             gen impl rustc_errors::Subdiagnostic for @Self {
                 fn add_to_diag_with<__G, __F>(
@@ -100,6 +103,7 @@ impl SubdiagnosticDerive {
                 }
             }
         });
+
         ret
     }
 }
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index beaaadd497d..2a593340849 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -220,19 +220,6 @@ pub enum MappingKind {
 }
 
 impl MappingKind {
-    /// Iterator over all coverage terms in this mapping kind.
-    pub fn terms(&self) -> impl Iterator<Item = CovTerm> {
-        let zero = || None.into_iter().chain(None);
-        let one = |a| Some(a).into_iter().chain(None);
-        let two = |a, b| Some(a).into_iter().chain(Some(b));
-        match *self {
-            Self::Code(term) => one(term),
-            Self::Branch { true_term, false_term } => two(true_term, false_term),
-            Self::MCDCBranch { true_term, false_term, .. } => two(true_term, false_term),
-            Self::MCDCDecision(_) => zero(),
-        }
-    }
-
     /// Returns a copy of this mapping kind, in which all coverage terms have
     /// been replaced with ones returned by the given function.
     pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self {
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 4e95e600b5a..bdd1eb11a38 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -393,7 +393,6 @@ pub(crate) struct AllocMap<'tcx> {
     alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>,
 
     /// Used to ensure that statics and functions only get one associated `AllocId`.
-    /// Should never contain a `GlobalAlloc::Memory`!
     //
     // FIXME: Should we just have two separate dedup maps for statics and functions each?
     dedup: FxHashMap<GlobalAlloc<'tcx>, AllocId>,
@@ -433,13 +432,13 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
-    /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we
-    /// don't want to dedup IDs for "real" memory!
+    /// Should not be used for mutable memory.
     fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
         let mut alloc_map = self.alloc_map.lock();
-        match alloc {
-            GlobalAlloc::Function { .. } | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {}
-            GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"),
+        if let GlobalAlloc::Memory(mem) = alloc {
+            if mem.inner().mutability.is_mut() {
+                bug!("trying to dedup-reserve mutable memory");
+            }
         }
         if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) {
             return alloc_id;
@@ -451,6 +450,12 @@ impl<'tcx> TyCtxt<'tcx> {
         id
     }
 
+    /// Generates an `AllocId` for a memory allocation. If the exact same memory has been
+    /// allocated before, this will return the same `AllocId`.
+    pub fn reserve_and_set_memory_dedup(self, mem: ConstAllocation<'tcx>) -> AllocId {
+        self.reserve_and_set_dedup(GlobalAlloc::Memory(mem))
+    }
+
     /// Generates an `AllocId` for a static or return a cached one in case this function has been
     /// called on the same static before.
     pub fn reserve_and_set_static_alloc(self, static_id: DefId) -> AllocId {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 82625ae3d47..223249952dc 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1545,6 +1545,9 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> std::fmt::Display
             // We are done.
             return write!(w, " {{}}");
         }
+        if tcx.sess.opts.unstable_opts.dump_mir_exclude_alloc_bytes {
+            return write!(w, " {{ .. }}");
+        }
         // Write allocation bytes.
         writeln!(w, " {{")?;
         write_allocation_bytes(tcx, alloc, w, "    ")?;
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 0d3c419748b..0031ded2440 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1016,14 +1016,14 @@ macro_rules! extra_body_methods {
 macro_rules! super_body {
     ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
         let span = $body.span;
-        if let Some(gen) = &$($mutability)? $body.coroutine {
-            if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
+        if let Some(coroutine) = &$($mutability)? $body.coroutine {
+            if let Some(yield_ty) = $(& $mutability)? coroutine.yield_ty {
                 $self.visit_ty(
                     yield_ty,
                     TyContext::YieldTy(SourceInfo::outermost(span))
                 );
             }
-            if let Some(resume_ty) = $(& $mutability)? gen.resume_ty {
+            if let Some(resume_ty) = $(& $mutability)? coroutine.resume_ty {
                 $self.visit_ty(
                     resume_ty,
                     TyContext::ResumeTy(SourceInfo::outermost(span))
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 33c27d41d86..817c7157b68 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2280,10 +2280,6 @@ rustc_queries! {
         desc { "whether the item should be made inlinable across crates" }
         separate_provide_extern
     }
-
-    query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
-        desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
-    }
 }
 
 rustc_query_append! { define_callbacks! }
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 7bc4c60f102..f659bf8125a 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -8,10 +8,6 @@ use crate::ty::{
     self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
 };
 
-mod cache;
-
-pub use cache::EvaluationCache;
-
 pub type Goal<'tcx, P> = ir::solve::Goal<TyCtxt<'tcx>, P>;
 pub type QueryInput<'tcx, P> = ir::solve::QueryInput<TyCtxt<'tcx>, P>;
 pub type QueryResult<'tcx> = ir::solve::QueryResult<TyCtxt<'tcx>>;
diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs
deleted file mode 100644
index 72a8d4eb405..00000000000
--- a/compiler/rustc_middle/src/traits/solve/cache.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-use super::{inspect, CanonicalInput, QueryResult};
-use crate::ty::TyCtxt;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::sync::Lock;
-use rustc_query_system::cache::WithDepNode;
-use rustc_query_system::dep_graph::DepNodeIndex;
-use rustc_session::Limit;
-use rustc_type_ir::solve::CacheData;
-
-/// The trait solver cache used by `-Znext-solver`.
-///
-/// FIXME(@lcnr): link to some official documentation of how
-/// this works.
-#[derive(Default)]
-pub struct EvaluationCache<'tcx> {
-    map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>,
-}
-
-impl<'tcx> rustc_type_ir::inherent::EvaluationCache<TyCtxt<'tcx>> for &'tcx EvaluationCache<'tcx> {
-    /// Insert a final result into the global cache.
-    fn insert(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        key: CanonicalInput<'tcx>,
-        proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>>,
-        additional_depth: usize,
-        encountered_overflow: bool,
-        cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
-        dep_node: DepNodeIndex,
-        result: QueryResult<'tcx>,
-    ) {
-        let mut map = self.map.borrow_mut();
-        let entry = map.entry(key).or_default();
-        let data = WithDepNode::new(dep_node, QueryData { result, proof_tree });
-        entry.cycle_participants.extend(cycle_participants);
-        if encountered_overflow {
-            entry.with_overflow.insert(additional_depth, data);
-        } else {
-            entry.success = Some(Success { data, additional_depth });
-        }
-
-        if cfg!(debug_assertions) {
-            drop(map);
-            let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow };
-            let actual = self.get(tcx, key, [], additional_depth);
-            if !actual.as_ref().is_some_and(|actual| expected == *actual) {
-                bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}");
-            }
-        }
-    }
-
-    /// Try to fetch a cached result, checking the recursion limit
-    /// and handling root goals of coinductive cycles.
-    ///
-    /// If this returns `Some` the cache result can be used.
-    fn get(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        key: CanonicalInput<'tcx>,
-        stack_entries: impl IntoIterator<Item = CanonicalInput<'tcx>>,
-        available_depth: usize,
-    ) -> Option<CacheData<TyCtxt<'tcx>>> {
-        let map = self.map.borrow();
-        let entry = map.get(&key)?;
-
-        for stack_entry in stack_entries {
-            if entry.cycle_participants.contains(&stack_entry) {
-                return None;
-            }
-        }
-
-        if let Some(ref success) = entry.success {
-            if Limit(available_depth).value_within_limit(success.additional_depth) {
-                let QueryData { result, proof_tree } = success.data.get(tcx);
-                return Some(CacheData {
-                    result,
-                    proof_tree,
-                    additional_depth: success.additional_depth,
-                    encountered_overflow: false,
-                });
-            }
-        }
-
-        entry.with_overflow.get(&available_depth).map(|e| {
-            let QueryData { result, proof_tree } = e.get(tcx);
-            CacheData {
-                result,
-                proof_tree,
-                additional_depth: available_depth,
-                encountered_overflow: true,
-            }
-        })
-    }
-}
-
-struct Success<'tcx> {
-    data: WithDepNode<QueryData<'tcx>>,
-    additional_depth: usize,
-}
-
-#[derive(Clone, Copy)]
-pub struct QueryData<'tcx> {
-    pub result: QueryResult<'tcx>,
-    pub proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>>,
-}
-
-/// The cache entry for a goal `CanonicalInput`.
-///
-/// This contains results whose computation never hit the
-/// recursion limit in `success`, and all results which hit
-/// the recursion limit in `with_overflow`.
-#[derive(Default)]
-struct CacheEntry<'tcx> {
-    success: Option<Success<'tcx>>,
-    /// We have to be careful when caching roots of cycles.
-    ///
-    /// See the doc comment of `StackEntry::cycle_participants` for more
-    /// details.
-    cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
-    with_overflow: FxHashMap<usize, WithDepNode<QueryData<'tcx>>>,
-}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index aee42bfe3aa..25070e6b042 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -59,6 +59,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{HirId, Node, TraitCandidate};
 use rustc_index::IndexVec;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
+use rustc_query_system::cache::WithDepNode;
 use rustc_query_system::dep_graph::DepNodeIndex;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
@@ -75,7 +76,7 @@ use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::solve::SolverMode;
 use rustc_type_ir::TyKind::*;
-use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo};
+use rustc_type_ir::{search_graph, CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo};
 use tracing::{debug, instrument};
 
 use std::assert_matches::assert_matches;
@@ -164,12 +165,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type Clause = Clause<'tcx>;
     type Clauses = ty::Clauses<'tcx>;
 
-    type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>;
+    type Tracked<T: fmt::Debug + Clone> = WithDepNode<T>;
+    fn mk_tracked<T: fmt::Debug + Clone>(
+        self,
+        data: T,
+        dep_node: DepNodeIndex,
+    ) -> Self::Tracked<T> {
+        WithDepNode::new(dep_node, data)
+    }
+    fn get_tracked<T: fmt::Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T {
+        tracked.get(self)
+    }
 
-    fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> {
+    fn with_global_cache<R>(
+        self,
+        mode: SolverMode,
+        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
+    ) -> R {
         match mode {
-            SolverMode::Normal => &self.new_solver_evaluation_cache,
-            SolverMode::Coherence => &self.new_solver_coherence_evaluation_cache,
+            SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()),
+            SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()),
         }
     }
 
@@ -1283,8 +1298,8 @@ pub struct GlobalCtxt<'tcx> {
     pub evaluation_cache: traits::EvaluationCache<'tcx>,
 
     /// Caches the results of goal evaluation in the new solver.
-    pub new_solver_evaluation_cache: solve::EvaluationCache<'tcx>,
-    pub new_solver_coherence_evaluation_cache: solve::EvaluationCache<'tcx>,
+    pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
+    pub new_solver_coherence_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
 
     pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>,
 
@@ -1427,11 +1442,12 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Allocates a read-only byte or string literal for `mir::interpret`.
-    pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
+    /// Returns the same `AllocId` if called again with the same bytes.
+    pub fn allocate_bytes_dedup(self, bytes: &[u8]) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
         let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes);
         let alloc = self.mk_const_alloc(alloc);
-        self.reserve_and_set_memory_alloc(alloc)
+        self.reserve_and_set_memory_dedup(alloc)
     }
 
     /// Returns a range of the start/end indices specified with the
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index c50a98e88fd..6e64e9bc4f8 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -541,7 +541,9 @@ impl<'tcx> Instance<'tcx> {
         // which means that rustc basically hangs.
         //
         // Bail out in these cases to avoid that bad user experience.
-        if !tcx.type_length_limit().value_within_limit(type_length(args)) {
+        if tcx.sess.opts.unstable_opts.enforce_type_length_limit
+            && !tcx.type_length_limit().value_within_limit(type_length(args))
+        {
             return Ok(None);
         }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index eb25aecd9ce..22a6786665c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1212,7 +1212,6 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) ->
         | RiscvInterruptM
         | RiscvInterruptS
         | CCmseNonSecureCall
-        | Wasm
         | Unadjusted => false,
         Rust | RustCall | RustCold | RustIntrinsic => {
             tcx.sess.panic_strategy() == PanicStrategy::Unwind
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 3b69058d3cb..be62a3d3736 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -140,7 +140,7 @@ fn lit_to_mir_constant<'tcx>(
             ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() }
         }
         (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
-            let id = tcx.allocate_bytes(data);
+            let id = tcx.allocate_bytes_dedup(data);
             ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
         }
         (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) =>
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
new file mode 100644
index 00000000000..2f540478674
--- /dev/null
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -0,0 +1,254 @@
+use rustc_middle::mir::*;
+use rustc_middle::thir::{self, *};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
+
+use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
+use crate::build::matches::{FlatPat, MatchPair, TestCase};
+use crate::build::Builder;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Builds and returns [`MatchPair`] trees, one for each pattern in
+    /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or
+    /// [`PatKind::Leaf`].
+    ///
+    /// Used internally by [`MatchPair::new`].
+    fn field_match_pairs<'pat>(
+        &mut self,
+        place: PlaceBuilder<'tcx>,
+        subpatterns: &'pat [FieldPat<'tcx>],
+    ) -> Vec<MatchPair<'pat, 'tcx>> {
+        subpatterns
+            .iter()
+            .map(|fieldpat| {
+                let place =
+                    place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
+                MatchPair::new(place, &fieldpat.pattern, self)
+            })
+            .collect()
+    }
+
+    /// Builds [`MatchPair`] trees for the prefix/middle/suffix parts of an
+    /// array pattern or slice pattern, and adds those trees to `match_pairs`.
+    ///
+    /// Used internally by [`MatchPair::new`].
+    fn prefix_slice_suffix<'pat>(
+        &mut self,
+        match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
+        place: &PlaceBuilder<'tcx>,
+        prefix: &'pat [Box<Pat<'tcx>>],
+        opt_slice: &'pat Option<Box<Pat<'tcx>>>,
+        suffix: &'pat [Box<Pat<'tcx>>],
+    ) {
+        let tcx = self.tcx;
+        let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
+            match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
+                ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
+                _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+            }
+        } else {
+            ((prefix.len() + suffix.len()).try_into().unwrap(), false)
+        };
+
+        match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
+            let elem =
+                ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
+            MatchPair::new(place.clone_project(elem), subpattern, self)
+        }));
+
+        if let Some(subslice_pat) = opt_slice {
+            let suffix_len = suffix.len() as u64;
+            let subslice = place.clone_project(PlaceElem::Subslice {
+                from: prefix.len() as u64,
+                to: if exact_size { min_length - suffix_len } else { suffix_len },
+                from_end: !exact_size,
+            });
+            match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
+        }
+
+        match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
+            let end_offset = (idx + 1) as u64;
+            let elem = ProjectionElem::ConstantIndex {
+                offset: if exact_size { min_length - end_offset } else { end_offset },
+                min_length,
+                from_end: !exact_size,
+            };
+            let place = place.clone_project(elem);
+            MatchPair::new(place, subpattern, self)
+        }));
+    }
+}
+
+impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
+    /// Recursively builds a `MatchPair` tree for the given pattern and its
+    /// subpatterns.
+    pub(in crate::build) fn new(
+        mut place_builder: PlaceBuilder<'tcx>,
+        pattern: &'pat Pat<'tcx>,
+        cx: &mut Builder<'_, 'tcx>,
+    ) -> MatchPair<'pat, 'tcx> {
+        // Force the place type to the pattern's type.
+        // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
+        if let Some(resolved) = place_builder.resolve_upvar(cx) {
+            place_builder = resolved;
+        }
+
+        // Only add the OpaqueCast projection if the given place is an opaque type and the
+        // expected type from the pattern is not.
+        let may_need_cast = match place_builder.base() {
+            PlaceBase::Local(local) => {
+                let ty =
+                    Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
+                ty != pattern.ty && ty.has_opaque_types()
+            }
+            _ => true,
+        };
+        if may_need_cast {
+            place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
+        }
+
+        let place = place_builder.try_to_place(cx);
+        let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
+        let mut subpairs = Vec::new();
+        let test_case = match pattern.kind {
+            PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
+
+            PatKind::Or { ref pats } => TestCase::Or {
+                pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
+            },
+
+            PatKind::Range(ref range) => {
+                if range.is_full_range(cx.tcx) == Some(true) {
+                    default_irrefutable()
+                } else {
+                    TestCase::Range(range)
+                }
+            }
+
+            PatKind::Constant { value } => TestCase::Constant { value },
+
+            PatKind::AscribeUserType {
+                ascription: thir::Ascription { ref annotation, variance },
+                ref subpattern,
+                ..
+            } => {
+                // Apply the type ascription to the value at `match_pair.place`
+                let ascription = place.map(|source| super::Ascription {
+                    annotation: annotation.clone(),
+                    source,
+                    variance,
+                });
+
+                subpairs.push(MatchPair::new(place_builder, subpattern, cx));
+                TestCase::Irrefutable { ascription, binding: None }
+            }
+
+            PatKind::Binding { mode, var, ref subpattern, .. } => {
+                let binding = place.map(|source| super::Binding {
+                    span: pattern.span,
+                    source,
+                    var_id: var,
+                    binding_mode: mode,
+                });
+
+                if let Some(subpattern) = subpattern.as_ref() {
+                    // this is the `x @ P` case; have to keep matching against `P` now
+                    subpairs.push(MatchPair::new(place_builder, subpattern, cx));
+                }
+                TestCase::Irrefutable { ascription: None, binding }
+            }
+
+            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
+                // Apply a type ascription for the inline constant to the value at `match_pair.place`
+                let ascription = place.map(|source| {
+                    let span = pattern.span;
+                    let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
+                    let args = ty::InlineConstArgs::new(
+                        cx.tcx,
+                        ty::InlineConstArgsParts {
+                            parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
+                            ty: cx.infcx.next_ty_var(span),
+                        },
+                    )
+                    .args;
+                    let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
+                        def.to_def_id(),
+                        ty::UserArgs { args, user_self_ty: None },
+                    ));
+                    let annotation = ty::CanonicalUserTypeAnnotation {
+                        inferred_ty: pattern.ty,
+                        span,
+                        user_ty: Box::new(user_ty),
+                    };
+                    super::Ascription { annotation, source, variance: ty::Contravariant }
+                });
+
+                subpairs.push(MatchPair::new(place_builder, pattern, cx));
+                TestCase::Irrefutable { ascription, binding: None }
+            }
+
+            PatKind::Array { ref prefix, ref slice, ref suffix } => {
+                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
+                default_irrefutable()
+            }
+            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
+                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
+
+                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
+                    default_irrefutable()
+                } else {
+                    TestCase::Slice {
+                        len: prefix.len() + suffix.len(),
+                        variable_length: slice.is_some(),
+                    }
+                }
+            }
+
+            PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
+                let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
+                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)
+                    }
+                }) && (adt_def.did().is_local()
+                    || !adt_def.is_variant_list_non_exhaustive());
+                if irrefutable {
+                    default_irrefutable()
+                } else {
+                    TestCase::Variant { adt_def, variant_index }
+                }
+            }
+
+            PatKind::Leaf { ref subpatterns } => {
+                subpairs = cx.field_match_pairs(place_builder, subpatterns);
+                default_irrefutable()
+            }
+
+            PatKind::Deref { ref subpattern } => {
+                subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
+                default_irrefutable()
+            }
+
+            PatKind::DerefPattern { ref subpattern, mutability } => {
+                // Create a new temporary for each deref pattern.
+                // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
+                let temp = cx.temp(
+                    Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
+                    pattern.span,
+                );
+                subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
+                TestCase::Deref { temp, mutability }
+            }
+
+            PatKind::Never => TestCase::Never,
+        };
+
+        MatchPair { place, test_case, subpairs, pattern }
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 5695c881ecc..98de4df3ce3 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -24,6 +24,7 @@ use tracing::{debug, instrument};
 use util::visit_bindings;
 
 // helper functions, broken out by category:
+mod match_pair;
 mod simplify;
 mod test;
 mod util;
@@ -1119,6 +1120,11 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
         }
     }
 
+    /// Returns whether the first match pair of this candidate is an or-pattern.
+    fn starts_with_or_pattern(&self) -> bool {
+        matches!(&*self.match_pairs, [MatchPair { test_case: TestCase::Or { .. }, .. }, ..])
+    }
+
     /// Visit the leaf candidates (those with no subcandidates) contained in
     /// this candidate.
     fn visit_leaves<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) {
@@ -1190,17 +1196,27 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> {
     }
 }
 
+/// Node in a tree of "match pairs", where each pair consists of a place to be
+/// tested, and a test to perform on that place.
+///
+/// Each node also has a list of subpairs (possibly empty) that must also match,
+/// and a reference to the THIR pattern it represents.
 #[derive(Debug, Clone)]
 pub(crate) struct MatchPair<'pat, 'tcx> {
     /// This place...
-    // This can be `None` if it referred to a non-captured place in a closure.
-    // Invariant: place.is_none() => test_case is Irrefutable
-    // In other words this must be `Some(_)` after simplification.
+    ///
+    /// ---
+    /// This can be `None` if it referred to a non-captured place in a closure.
+    ///
+    /// Invariant: Can only be `None` when `test_case` is `Irrefutable`.
+    /// Therefore this must be `Some(_)` after simplification.
     place: Option<Place<'tcx>>,
 
     /// ... must pass this test...
-    // Invariant: after creation and simplification in `Candidate::new()`, this must not be
-    // `Irrefutable`.
+    ///
+    /// ---
+    /// Invariant: after creation and simplification in [`FlatPat::new`],
+    /// this must not be [`TestCase::Irrefutable`].
     test_case: TestCase<'pat, 'tcx>,
 
     /// ... and these subpairs must match.
@@ -1308,11 +1324,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         candidates: &mut [&mut Candidate<'pat, 'tcx>],
         refutable: bool,
     ) -> BasicBlock {
+        // This will generate code to test scrutinee_place and branch to the appropriate arm block.
         // See the doc comment on `match_candidates` for why we have an otherwise block.
-        let otherwise_block = self.cfg.start_new_block();
-
-        // This will generate code to test scrutinee_place and branch to the appropriate arm block
-        self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates);
+        let otherwise_block =
+            self.match_candidates(match_start_span, scrutinee_span, block, candidates);
 
         // Link each leaf candidate to the `false_edge_start_block` of the next one.
         let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None;
@@ -1363,27 +1378,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         otherwise_block
     }
 
-    /// The main match algorithm. It begins with a set of candidates
-    /// `candidates` and has the job of generating code to determine
-    /// which of these candidates, if any, is the correct one. The
+    /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of
+    /// generating code that branches to an appropriate block if the scrutinee matches one of these
+    /// candidates. The
     /// candidates are sorted such that the first item in the list
     /// has the highest priority. When a candidate is found to match
     /// the value, we will set and generate a branch to the appropriate
     /// pre-binding block.
     ///
-    /// If we find that *NONE* of the candidates apply, we branch to `otherwise_block`.
+    /// If none of the candidates apply, we continue to the returned `otherwise_block`.
     ///
     /// It might be surprising that the input can be non-exhaustive.
-    /// Indeed, initially, it is not, because all matches are
+    /// Indeed, for matches, initially, it is not, because all matches are
     /// exhaustive in Rust. But during processing we sometimes divide
     /// up the list of candidates and recurse with a non-exhaustive
     /// list. This is how our lowering approach (called "backtracking
     /// automaton" in the literature) works.
     /// See [`Builder::test_candidates`] for more details.
     ///
-    /// If `fake_borrows` is `Some`, then places which need fake borrows
-    /// will be added to it.
-    ///
     /// For an example of how we use `otherwise_block`, consider:
     /// ```
     /// # fn foo((x, y): (bool, bool)) -> u32 {
@@ -1408,7 +1420,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// }
     /// if y {
     ///     if x {
-    ///         // This is actually unreachable because the `(true, true)` case was handled above.
+    ///         // This is actually unreachable because the `(true, true)` case was handled above,
+    ///         // but we don't know that from within the lowering algorithm.
     ///         // continue
     ///     } else {
     ///         return 3
@@ -1425,161 +1438,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`].
     ///
     /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
-    /// code size at the expense of non-optimal code paths.
+    /// code size so we accept non-optimal code paths.
     #[instrument(skip(self), level = "debug")]
-    fn match_candidates<'pat>(
+    fn match_candidates(
         &mut self,
         span: Span,
         scrutinee_span: Span,
         start_block: BasicBlock,
-        otherwise_block: BasicBlock,
-        candidates: &mut [&mut Candidate<'pat, 'tcx>],
-    ) {
-        // We process or-patterns here. If any candidate starts with an or-pattern, we have to
-        // expand the or-pattern before we can proceed further.
-        //
-        // We can't expand them freely however. The rule is: if the candidate has an or-pattern as
-        // its only remaining match pair, we can expand it freely. If it has other match pairs, we
-        // can expand it but we can't process more candidates after it.
-        //
-        // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following,
-        // or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2`
-        // cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same
-        // set of candidates, when we reach the block that tests `false` we don't know whether we
-        // came from `1` or `2`, hence we can't know where to branch on failure.
-        // ```ignore(illustrative)
-        // match (1, true) {
-        //     (1 | 2, false) => {},
-        //     (2, _) => {},
-        //     _ => {}
-        // }
-        // ```
-        //
-        // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
-        // and process both halves separately.
-        let mut expand_until = 0;
-        for (i, candidate) in candidates.iter().enumerate() {
-            if matches!(
-                &*candidate.match_pairs,
-                [MatchPair { test_case: TestCase::Or { .. }, .. }, ..]
-            ) {
-                expand_until = i + 1;
-                if candidate.match_pairs.len() > 1 {
-                    break;
-                }
-            }
-            if expand_until != 0 {
-                expand_until = i + 1;
-            }
-        }
-        let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);
-
+        candidates: &mut [&mut Candidate<'_, 'tcx>],
+    ) -> BasicBlock {
         ensure_sufficient_stack(|| {
-            if candidates_to_expand.is_empty() {
-                // No candidates start with an or-pattern, we can continue.
-                self.match_expanded_candidates(
-                    span,
-                    scrutinee_span,
-                    start_block,
-                    otherwise_block,
-                    remaining_candidates,
-                );
-            } else {
-                // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
-                let mut expanded_candidates = Vec::new();
-                for candidate in candidates_to_expand.iter_mut() {
-                    if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] =
-                        &*candidate.match_pairs
-                    {
-                        let or_match_pair = candidate.match_pairs.remove(0);
-                        // Expand the or-pattern into subcandidates.
-                        self.create_or_subcandidates(candidate, or_match_pair);
-                        // Collect the newly created subcandidates.
-                        for subcandidate in candidate.subcandidates.iter_mut() {
-                            expanded_candidates.push(subcandidate);
-                        }
-                    } else {
-                        expanded_candidates.push(candidate);
-                    }
-                }
-
-                // Process the expanded candidates.
-                let remainder_start = self.cfg.start_new_block();
-                // There might be new or-patterns obtained from expanding the old ones, so we call
-                // `match_candidates` again.
-                self.match_candidates(
-                    span,
-                    scrutinee_span,
-                    start_block,
-                    remainder_start,
-                    expanded_candidates.as_mut_slice(),
-                );
-
-                // Simplify subcandidates and process any leftover match pairs.
-                for candidate in candidates_to_expand {
-                    if !candidate.subcandidates.is_empty() {
-                        self.finalize_or_candidate(span, scrutinee_span, candidate);
-                    }
-                }
-
-                // Process the remaining candidates.
-                self.match_candidates(
-                    span,
-                    scrutinee_span,
-                    remainder_start,
-                    otherwise_block,
-                    remaining_candidates,
-                );
-            }
-        });
+            self.match_candidates_inner(span, scrutinee_span, start_block, candidates)
+        })
     }
 
-    /// Construct the decision tree for `candidates`. Caller must ensure that no candidate in
-    /// `candidates` starts with an or-pattern.
-    fn match_expanded_candidates(
+    /// Construct the decision tree for `candidates`. Don't call this, call `match_candidates`
+    /// instead to reserve sufficient stack space.
+    fn match_candidates_inner(
         &mut self,
         span: Span,
         scrutinee_span: Span,
         mut start_block: BasicBlock,
-        otherwise_block: BasicBlock,
         candidates: &mut [&mut Candidate<'_, 'tcx>],
-    ) {
+    ) -> BasicBlock {
         if let [first, ..] = candidates {
             if first.false_edge_start_block.is_none() {
                 first.false_edge_start_block = Some(start_block);
             }
         }
 
-        match candidates {
+        // Process a prefix of the candidates.
+        let rest = match candidates {
             [] => {
-                // If there are no candidates that still need testing, we're done. Since all matches are
-                // exhaustive, execution should never reach this point.
-                let source_info = self.source_info(span);
-                self.cfg.goto(start_block, source_info, otherwise_block);
+                // If there are no candidates that still need testing, we're done.
+                return start_block;
             }
             [first, remaining @ ..] if first.match_pairs.is_empty() => {
                 // The first candidate has satisfied all its match pairs; we link it up and continue
                 // with the remaining candidates.
-                start_block = self.select_matched_candidate(first, start_block);
-                self.match_expanded_candidates(
-                    span,
-                    scrutinee_span,
-                    start_block,
-                    otherwise_block,
-                    remaining,
-                )
+                let remainder_start = self.select_matched_candidate(first, start_block);
+                remainder_start.and(remaining)
+            }
+            candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => {
+                // If any candidate starts with an or-pattern, we have to expand the or-pattern before we
+                // can proceed further.
+                self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates)
             }
             candidates => {
                 // The first candidate has some unsatisfied match pairs; we proceed to do more tests.
-                self.test_candidates(
-                    span,
-                    scrutinee_span,
-                    candidates,
-                    start_block,
-                    otherwise_block,
-                );
+                self.test_candidates(span, scrutinee_span, candidates, start_block)
             }
-        }
+        };
+
+        // Process any candidates that remain.
+        let remaining_candidates = unpack!(start_block = rest);
+        self.match_candidates(span, scrutinee_span, start_block, remaining_candidates)
     }
 
     /// Link up matched candidates.
@@ -1624,6 +1537,102 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         otherwise_block
     }
 
+    /// Takes a list of candidates such that some of the candidates' first match pairs are
+    /// or-patterns. This expands as many or-patterns as possible and processes the resulting
+    /// candidates. Returns the unprocessed candidates if any.
+    fn expand_and_match_or_candidates<'pat, 'b, 'c>(
+        &mut self,
+        span: Span,
+        scrutinee_span: Span,
+        start_block: BasicBlock,
+        candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
+    ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> {
+        // We can't expand or-patterns freely. The rule is: if the candidate has an
+        // or-pattern as its only remaining match pair, we can expand it freely. If it has
+        // other match pairs, we can expand it but we can't process more candidates after
+        // it.
+        //
+        // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the
+        // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it
+        // so the `1` and `2` cases branch to a same block (which then tests `false`). If we
+        // took `(2, _)` in the same set of candidates, when we reach the block that tests
+        // `false` we don't know whether we came from `1` or `2`, hence we can't know where
+        // to branch on failure.
+        //
+        // ```ignore(illustrative)
+        // match (1, true) {
+        //     (1 | 2, false) => {},
+        //     (2, _) => {},
+        //     _ => {}
+        // }
+        // ```
+        //
+        // We therefore split the `candidates` slice in two, expand or-patterns in the first half,
+        // and process the rest separately.
+        let mut expand_until = 0;
+        for (i, candidate) in candidates.iter().enumerate() {
+            expand_until = i + 1;
+            if candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern() {
+                // The candidate has an or-pattern as well as more match pairs: we must
+                // split the candidates list here.
+                break;
+            }
+        }
+        let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);
+
+        // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
+        let mut expanded_candidates = Vec::new();
+        for candidate in candidates_to_expand.iter_mut() {
+            if candidate.starts_with_or_pattern() {
+                let or_match_pair = candidate.match_pairs.remove(0);
+                // Expand the or-pattern into subcandidates.
+                self.create_or_subcandidates(candidate, or_match_pair);
+                // Collect the newly created subcandidates.
+                for subcandidate in candidate.subcandidates.iter_mut() {
+                    expanded_candidates.push(subcandidate);
+                }
+            } else {
+                expanded_candidates.push(candidate);
+            }
+        }
+
+        // Process the expanded candidates.
+        let remainder_start = self.match_candidates(
+            span,
+            scrutinee_span,
+            start_block,
+            expanded_candidates.as_mut_slice(),
+        );
+
+        // Simplify subcandidates and process any leftover match pairs.
+        for candidate in candidates_to_expand {
+            if !candidate.subcandidates.is_empty() {
+                self.finalize_or_candidate(span, scrutinee_span, candidate);
+            }
+        }
+
+        remainder_start.and(remaining_candidates)
+    }
+
+    /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
+    /// subcandidate. Any candidate that has been expanded that way should be passed to
+    /// `finalize_or_candidate` after its subcandidates have been processed.
+    fn create_or_subcandidates<'pat>(
+        &mut self,
+        candidate: &mut Candidate<'pat, 'tcx>,
+        match_pair: MatchPair<'pat, 'tcx>,
+    ) {
+        let TestCase::Or { pats } = match_pair.test_case else { bug!() };
+        debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
+        candidate.or_span = Some(match_pair.pattern.span);
+        candidate.subcandidates = pats
+            .into_vec()
+            .into_iter()
+            .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
+            .collect();
+        candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
+    }
+
     /// Simplify subcandidates and process any leftover match pairs. The candidate should have been
     /// expanded with `create_or_subcandidates`.
     ///
@@ -1690,6 +1699,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.merge_trivial_subcandidates(candidate);
 
         if !candidate.match_pairs.is_empty() {
+            let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span);
+            let source_info = self.source_info(or_span);
             // If more match pairs remain, test them after each subcandidate.
             // We could add them to the or-candidates before the call to `test_or_pattern` but this
             // would make it impossible to detect simplifiable or-patterns. That would guarantee
@@ -1703,6 +1714,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 assert!(leaf_candidate.match_pairs.is_empty());
                 leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
                 let or_start = leaf_candidate.pre_binding_block.unwrap();
+                let otherwise =
+                    self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]);
                 // In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
                 // R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
                 // directly to `last_otherwise`. If there is a guard,
@@ -1713,36 +1726,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 } else {
                     last_otherwise.unwrap()
                 };
-                self.match_candidates(
-                    span,
-                    scrutinee_span,
-                    or_start,
-                    or_otherwise,
-                    &mut [leaf_candidate],
-                );
+                self.cfg.goto(otherwise, source_info, or_otherwise);
             });
         }
     }
 
-    /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
-    /// subcandidate. Any candidate that has been expanded that way should be passed to
-    /// `finalize_or_candidate` after its subcandidates have been processed.
-    fn create_or_subcandidates<'pat>(
-        &mut self,
-        candidate: &mut Candidate<'pat, 'tcx>,
-        match_pair: MatchPair<'pat, 'tcx>,
-    ) {
-        let TestCase::Or { pats } = match_pair.test_case else { bug!() };
-        debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
-        candidate.or_span = Some(match_pair.pattern.span);
-        candidate.subcandidates = pats
-            .into_vec()
-            .into_iter()
-            .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
-            .collect();
-        candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;
-    }
-
     /// Try to merge all of the subcandidates of the given candidate into one. This avoids
     /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been
     /// expanded with `create_or_subcandidates`.
@@ -1992,14 +1980,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// }
     /// # }
     /// ```
+    ///
+    /// We return the unprocessed candidates.
     fn test_candidates<'pat, 'b, 'c>(
         &mut self,
         span: Span,
         scrutinee_span: Span,
         candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
         start_block: BasicBlock,
-        otherwise_block: BasicBlock,
-    ) {
+    ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> {
         // Extract the match-pair from the highest priority candidate and build a test from it.
         let (match_place, test) = self.pick_test(candidates);
 
@@ -2010,33 +1999,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         // The block that we should branch to if none of the
         // `target_candidates` match.
-        let remainder_start = if !remaining_candidates.is_empty() {
-            let remainder_start = self.cfg.start_new_block();
-            self.match_candidates(
-                span,
-                scrutinee_span,
-                remainder_start,
-                otherwise_block,
-                remaining_candidates,
-            );
-            remainder_start
-        } else {
-            otherwise_block
-        };
+        let remainder_start = self.cfg.start_new_block();
 
         // For each outcome of test, process the candidates that still apply.
         let target_blocks: FxIndexMap<_, _> = target_candidates
             .into_iter()
             .map(|(branch, mut candidates)| {
-                let candidate_start = self.cfg.start_new_block();
-                self.match_candidates(
-                    span,
-                    scrutinee_span,
-                    candidate_start,
-                    remainder_start,
-                    &mut *candidates,
-                );
-                (branch, candidate_start)
+                let branch_start = self.cfg.start_new_block();
+                let branch_otherwise =
+                    self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates);
+                let source_info = self.source_info(span);
+                self.cfg.goto(branch_otherwise, source_info, remainder_start);
+                (branch, branch_start)
             })
             .collect();
 
@@ -2050,6 +2024,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             &test,
             target_blocks,
         );
+
+        remainder_start.and(remaining_candidates)
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 3bec154e1df..e67fc843285 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,78 +1,15 @@
 use std::marker::PhantomData;
 
-use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
+use crate::build::expr::as_place::PlaceBase;
 use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
 use crate::build::Builder;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_middle::mir::*;
-use rustc_middle::thir::{self, *};
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::Ty;
 use rustc_span::Span;
 use tracing::debug;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    pub(crate) fn field_match_pairs<'pat>(
-        &mut self,
-        place: PlaceBuilder<'tcx>,
-        subpatterns: &'pat [FieldPat<'tcx>],
-    ) -> Vec<MatchPair<'pat, 'tcx>> {
-        subpatterns
-            .iter()
-            .map(|fieldpat| {
-                let place =
-                    place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
-                MatchPair::new(place, &fieldpat.pattern, self)
-            })
-            .collect()
-    }
-
-    pub(crate) fn prefix_slice_suffix<'pat>(
-        &mut self,
-        match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
-        place: &PlaceBuilder<'tcx>,
-        prefix: &'pat [Box<Pat<'tcx>>],
-        opt_slice: &'pat Option<Box<Pat<'tcx>>>,
-        suffix: &'pat [Box<Pat<'tcx>>],
-    ) {
-        let tcx = self.tcx;
-        let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
-            match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
-                ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
-                _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
-            }
-        } else {
-            ((prefix.len() + suffix.len()).try_into().unwrap(), false)
-        };
-
-        match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
-            let elem =
-                ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
-            MatchPair::new(place.clone_project(elem), subpattern, self)
-        }));
-
-        if let Some(subslice_pat) = opt_slice {
-            let suffix_len = suffix.len() as u64;
-            let subslice = place.clone_project(PlaceElem::Subslice {
-                from: prefix.len() as u64,
-                to: if exact_size { min_length - suffix_len } else { suffix_len },
-                from_end: !exact_size,
-            });
-            match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
-        }
-
-        match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
-            let end_offset = (idx + 1) as u64;
-            let elem = ProjectionElem::ConstantIndex {
-                offset: if exact_size { min_length - end_offset } else { end_offset },
-                min_length,
-                from_end: !exact_size,
-            };
-            let place = place.clone_project(elem);
-            MatchPair::new(place, subpattern, self)
-        }));
-    }
-
     /// Creates a false edge to `imaginary_target` and a real edge to
     /// real_target. If `imaginary_target` is none, or is the same as the real
     /// target, a Goto is generated instead to simplify the generated MIR.
@@ -96,181 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     }
 }
 
-impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
-    /// Recursively builds a `MatchPair` tree for the given pattern and its
-    /// subpatterns.
-    pub(in crate::build) fn new(
-        mut place_builder: PlaceBuilder<'tcx>,
-        pattern: &'pat Pat<'tcx>,
-        cx: &mut Builder<'_, 'tcx>,
-    ) -> MatchPair<'pat, 'tcx> {
-        // Force the place type to the pattern's type.
-        // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
-        if let Some(resolved) = place_builder.resolve_upvar(cx) {
-            place_builder = resolved;
-        }
-
-        // Only add the OpaqueCast projection if the given place is an opaque type and the
-        // expected type from the pattern is not.
-        let may_need_cast = match place_builder.base() {
-            PlaceBase::Local(local) => {
-                let ty =
-                    Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
-                ty != pattern.ty && ty.has_opaque_types()
-            }
-            _ => true,
-        };
-        if may_need_cast {
-            place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
-        }
-
-        let place = place_builder.try_to_place(cx);
-        let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
-        let mut subpairs = Vec::new();
-        let test_case = match pattern.kind {
-            PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
-
-            PatKind::Or { ref pats } => TestCase::Or {
-                pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
-            },
-
-            PatKind::Range(ref range) => {
-                if range.is_full_range(cx.tcx) == Some(true) {
-                    default_irrefutable()
-                } else {
-                    TestCase::Range(range)
-                }
-            }
-
-            PatKind::Constant { value } => TestCase::Constant { value },
-
-            PatKind::AscribeUserType {
-                ascription: thir::Ascription { ref annotation, variance },
-                ref subpattern,
-                ..
-            } => {
-                // Apply the type ascription to the value at `match_pair.place`
-                let ascription = place.map(|source| super::Ascription {
-                    annotation: annotation.clone(),
-                    source,
-                    variance,
-                });
-
-                subpairs.push(MatchPair::new(place_builder, subpattern, cx));
-                TestCase::Irrefutable { ascription, binding: None }
-            }
-
-            PatKind::Binding { mode, var, ref subpattern, .. } => {
-                let binding = place.map(|source| super::Binding {
-                    span: pattern.span,
-                    source,
-                    var_id: var,
-                    binding_mode: mode,
-                });
-
-                if let Some(subpattern) = subpattern.as_ref() {
-                    // this is the `x @ P` case; have to keep matching against `P` now
-                    subpairs.push(MatchPair::new(place_builder, subpattern, cx));
-                }
-                TestCase::Irrefutable { ascription: None, binding }
-            }
-
-            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
-                // Apply a type ascription for the inline constant to the value at `match_pair.place`
-                let ascription = place.map(|source| {
-                    let span = pattern.span;
-                    let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
-                    let args = ty::InlineConstArgs::new(
-                        cx.tcx,
-                        ty::InlineConstArgsParts {
-                            parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
-                            ty: cx.infcx.next_ty_var(span),
-                        },
-                    )
-                    .args;
-                    let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                        def.to_def_id(),
-                        ty::UserArgs { args, user_self_ty: None },
-                    ));
-                    let annotation = ty::CanonicalUserTypeAnnotation {
-                        inferred_ty: pattern.ty,
-                        span,
-                        user_ty: Box::new(user_ty),
-                    };
-                    super::Ascription { annotation, source, variance: ty::Contravariant }
-                });
-
-                subpairs.push(MatchPair::new(place_builder, pattern, cx));
-                TestCase::Irrefutable { ascription, binding: None }
-            }
-
-            PatKind::Array { ref prefix, ref slice, ref suffix } => {
-                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
-                default_irrefutable()
-            }
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
-
-                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
-                    default_irrefutable()
-                } else {
-                    TestCase::Slice {
-                        len: prefix.len() + suffix.len(),
-                        variable_length: slice.is_some(),
-                    }
-                }
-            }
-
-            PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
-                let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
-                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)
-                    }
-                }) && (adt_def.did().is_local()
-                    || !adt_def.is_variant_list_non_exhaustive());
-                if irrefutable {
-                    default_irrefutable()
-                } else {
-                    TestCase::Variant { adt_def, variant_index }
-                }
-            }
-
-            PatKind::Leaf { ref subpatterns } => {
-                subpairs = cx.field_match_pairs(place_builder, subpatterns);
-                default_irrefutable()
-            }
-
-            PatKind::Deref { ref subpattern } => {
-                subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
-                default_irrefutable()
-            }
-
-            PatKind::DerefPattern { ref subpattern, mutability } => {
-                // Create a new temporary for each deref pattern.
-                // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
-                let temp = cx.temp(
-                    Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
-                    pattern.span,
-                );
-                subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
-                TestCase::Deref { temp, mutability }
-            }
-
-            PatKind::Never => TestCase::Never,
-        };
-
-        MatchPair { place, test_case, subpairs, pattern }
-    }
-}
-
 /// Determine the set of places that have to be stable across match guards.
 ///
 /// Returns a list of places that need a fake borrow along with a local to store it.
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 09cdb055a3e..6eaed0f7753 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -402,7 +402,7 @@ where
 /// building up a `GenKillSet` and then throwing it away.
 pub trait GenKill<T> {
     /// Inserts `elem` into the state vector.
-    fn gen(&mut self, elem: T);
+    fn gen_(&mut self, elem: T);
 
     /// Removes `elem` from the state vector.
     fn kill(&mut self, elem: T);
@@ -410,7 +410,7 @@ pub trait GenKill<T> {
     /// Calls `gen` for each element in `elems`.
     fn gen_all(&mut self, elems: impl IntoIterator<Item = T>) {
         for elem in elems {
-            self.gen(elem);
+            self.gen_(elem);
         }
     }
 
@@ -424,12 +424,12 @@ pub trait GenKill<T> {
 
 /// Stores a transfer function for a gen/kill problem.
 ///
-/// Calling `gen`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be
-/// applied multiple times efficiently. When there are multiple calls to `gen` and/or `kill` for
+/// Calling `gen_`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be
+/// applied multiple times efficiently. When there are multiple calls to `gen_` and/or `kill` for
 /// the same element, the most recent one takes precedence.
 #[derive(Clone)]
 pub struct GenKillSet<T> {
-    gen: HybridBitSet<T>,
+    gen_: HybridBitSet<T>,
     kill: HybridBitSet<T>,
 }
 
@@ -437,31 +437,31 @@ impl<T: Idx> GenKillSet<T> {
     /// Creates a new transfer function that will leave the dataflow state unchanged.
     pub fn identity(universe: usize) -> Self {
         GenKillSet {
-            gen: HybridBitSet::new_empty(universe),
+            gen_: HybridBitSet::new_empty(universe),
             kill: HybridBitSet::new_empty(universe),
         }
     }
 
     pub fn apply(&self, state: &mut impl BitSetExt<T>) {
-        state.union(&self.gen);
+        state.union(&self.gen_);
         state.subtract(&self.kill);
     }
 }
 
 impl<T: Idx> GenKill<T> for GenKillSet<T> {
-    fn gen(&mut self, elem: T) {
-        self.gen.insert(elem);
+    fn gen_(&mut self, elem: T) {
+        self.gen_.insert(elem);
         self.kill.remove(elem);
     }
 
     fn kill(&mut self, elem: T) {
         self.kill.insert(elem);
-        self.gen.remove(elem);
+        self.gen_.remove(elem);
     }
 }
 
 impl<T: Idx> GenKill<T> for BitSet<T> {
-    fn gen(&mut self, elem: T) {
+    fn gen_(&mut self, elem: T) {
         self.insert(elem);
     }
 
@@ -471,7 +471,7 @@ impl<T: Idx> GenKill<T> for BitSet<T> {
 }
 
 impl<T: Idx> GenKill<T> for ChunkedBitSet<T> {
-    fn gen(&mut self, elem: T) {
+    fn gen_(&mut self, elem: T) {
         self.insert(elem);
     }
 
@@ -481,11 +481,11 @@ impl<T: Idx> GenKill<T> for ChunkedBitSet<T> {
 }
 
 impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
-    fn gen(&mut self, elem: T) {
+    fn gen_(&mut self, elem: T) {
         match self {
             // If the state is not reachable, adding an element does nothing.
             MaybeReachable::Unreachable => {}
-            MaybeReachable::Reachable(set) => set.gen(elem),
+            MaybeReachable::Reachable(set) => set.gen_(elem),
         }
     }
 
@@ -499,7 +499,7 @@ impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
 }
 
 impl<T: Idx> GenKill<T> for lattice::Dual<BitSet<T>> {
-    fn gen(&mut self, elem: T) {
+    fn gen_(&mut self, elem: T) {
         self.0.insert(elem);
     }
 
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 574da949b0e..885fdd0d58b 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -97,7 +97,7 @@ where
             Rvalue::AddressOf(_, borrowed_place)
             | Rvalue::Ref(_, BorrowKind::Mut { .. } | BorrowKind::Shared, borrowed_place) => {
                 if !borrowed_place.is_indirect() {
-                    self.trans.gen(borrowed_place.local);
+                    self.trans.gen_(borrowed_place.local);
                 }
             }
 
@@ -131,7 +131,7 @@ where
                 //
                 // [#61069]: https://github.com/rust-lang/rust/pull/61069
                 if !dropped_place.is_indirect() {
-                    self.trans.gen(dropped_place.local);
+                    self.trans.gen_(dropped_place.local);
                 }
             }
 
@@ -159,8 +159,8 @@ pub fn borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
 
     impl GenKill<Local> for Borrowed {
         #[inline]
-        fn gen(&mut self, elem: Local) {
-            self.0.gen(elem)
+        fn gen_(&mut self, elem: Local) {
+            self.0.gen_(elem)
         }
         #[inline]
         fn kill(&mut self, _: Local) {
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index ffcf630b653..a9bceeccdce 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -283,7 +283,7 @@ impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> {
     ) {
         match state {
             DropFlagState::Absent => trans.kill(path),
-            DropFlagState::Present => trans.gen(path),
+            DropFlagState::Present => trans.gen_(path),
         }
     }
 }
@@ -295,7 +295,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, '_, 'tcx> {
         state: DropFlagState,
     ) {
         match state {
-            DropFlagState::Absent => trans.gen(path),
+            DropFlagState::Absent => trans.gen_(path),
             DropFlagState::Present => trans.kill(path),
         }
     }
@@ -309,7 +309,7 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
     ) {
         match state {
             DropFlagState::Absent => trans.kill(path),
-            DropFlagState::Present => trans.gen(path),
+            DropFlagState::Present => trans.gen_(path),
         }
     }
 }
@@ -331,7 +331,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
             MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len()));
         drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
-            state.gen(path);
+            state.gen_(path);
         });
     }
 }
@@ -362,7 +362,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
             && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref())
         {
             on_all_children_bits(self.move_data(), mpi, |child| {
-                trans.gen(child);
+                trans.gen_(child);
             })
         }
     }
@@ -400,7 +400,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> {
                 self.move_data(),
                 self.move_data().rev_lookup.find(place.as_ref()),
                 |mpi| {
-                    trans.gen(mpi);
+                    trans.gen_(mpi);
                 },
             );
         });
@@ -572,7 +572,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> {
                 self.move_data(),
                 enum_place,
                 variant,
-                |mpi| trans.gen(mpi),
+                |mpi| trans.gen_(mpi),
             );
         });
     }
@@ -643,7 +643,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
                 self.move_data(),
                 self.move_data().rev_lookup.find(place.as_ref()),
                 |mpi| {
-                    trans.gen(mpi);
+                    trans.gen_(mpi);
                 },
             );
         });
@@ -738,7 +738,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> {
 
         let call_loc = self.body.terminator_loc(block);
         for init_index in &init_loc_map[call_loc] {
-            trans.gen(*init_index);
+            trans.gen_(*init_index);
         }
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 334fa9976f0..48bdb131601 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -116,7 +116,7 @@ where
                     self.0.kill(place.local);
                 }
             }
-            Some(DefUse::Use) => self.0.gen(place.local),
+            Some(DefUse::Use) => self.0.gen_(place.local),
             None => {}
         }
 
@@ -154,7 +154,7 @@ impl DefUse {
     fn apply(trans: &mut impl GenKill<Local>, place: Place<'_>, context: PlaceContext) {
         match DefUse::for_place(place, context) {
             Some(DefUse::Def) => trans.kill(place.local),
-            Some(DefUse::Use) => trans.gen(place.local),
+            Some(DefUse::Use) => trans.gen_(place.local),
             None => {}
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index f850a710277..682cec12f1f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -54,7 +54,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
         _: Location,
     ) {
         match stmt.kind {
-            StatementKind::StorageLive(l) => trans.gen(l),
+            StatementKind::StorageLive(l) => trans.gen_(l),
             StatementKind::StorageDead(l) => trans.kill(l),
             _ => (),
         }
@@ -127,7 +127,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> {
     ) {
         match stmt.kind {
             StatementKind::StorageLive(l) => trans.kill(l),
-            StatementKind::StorageDead(l) => trans.gen(l),
+            StatementKind::StorageDead(l) => trans.gen_(l),
             _ => (),
         }
     }
@@ -208,7 +208,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
             StatementKind::Assign(box (place, _))
             | StatementKind::SetDiscriminant { box place, .. }
             | StatementKind::Deinit(box place) => {
-                trans.gen(place.local);
+                trans.gen_(place.local);
             }
 
             // Nothing to do for these. Match exhaustively so this fails to compile when new
@@ -250,7 +250,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
 
         match &terminator.kind {
             TerminatorKind::Call { destination, .. } => {
-                trans.gen(destination.local);
+                trans.gen_(destination.local);
             }
 
             // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
@@ -265,7 +265,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
                         InlineAsmOperand::Out { place, .. }
                         | InlineAsmOperand::InOut { out_place: place, .. } => {
                             if let Some(place) = place {
-                                trans.gen(place.local);
+                                trans.gen_(place.local);
                             }
                         }
                         InlineAsmOperand::In { .. }
@@ -341,7 +341,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
         _block: BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        return_places.for_each(|place| trans.gen(place.local));
+        return_places.for_each(|place| trans.gen_(place.local));
     }
 }
 
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 1582c2e8a90..c9f5d38fe2c 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -32,15 +32,16 @@
 //! Because of that, we can assume that the only way to change the value behind a tracked place is
 //! by direct assignment.
 
-use std::collections::VecDeque;
 use std::fmt::{Debug, Formatter};
 use std::ops::Range;
 
-use rustc_data_structures::fx::{FxHashMap, StdEntry};
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_middle::bug;
+use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -58,7 +59,7 @@ pub trait ValueAnalysis<'tcx> {
 
     const NAME: &'static str;
 
-    fn map(&self) -> &Map;
+    fn map(&self) -> &Map<'tcx>;
 
     fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::Value>) {
         self.super_statement(statement, state)
@@ -523,12 +524,12 @@ impl<V: Clone + HasBottom> State<V> {
     }
 
     /// Assign `value` to all places that are contained in `place` or may alias one.
-    pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
+    pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map<'_>, value: V) {
         self.flood_with_tail_elem(place, None, map, value)
     }
 
     /// Assign `TOP` to all places that are contained in `place` or may alias one.
-    pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map)
+    pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map<'_>)
     where
         V: HasTop,
     {
@@ -536,12 +537,12 @@ impl<V: Clone + HasBottom> State<V> {
     }
 
     /// Assign `value` to the discriminant of `place` and all places that may alias it.
-    fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
+    fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map<'_>, value: V) {
         self.flood_with_tail_elem(place, Some(TrackElem::Discriminant), map, value)
     }
 
     /// Assign `TOP` to the discriminant of `place` and all places that may alias it.
-    pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map)
+    pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map<'_>)
     where
         V: HasTop,
     {
@@ -559,7 +560,7 @@ impl<V: Clone + HasBottom> State<V> {
         &mut self,
         place: PlaceRef<'_>,
         tail_elem: Option<TrackElem>,
-        map: &Map,
+        map: &Map<'_>,
         value: V,
     ) {
         let State::Reachable(values) = self else { return };
@@ -570,7 +571,7 @@ impl<V: Clone + HasBottom> State<V> {
     /// This does nothing if the place is not tracked.
     ///
     /// The target place must have been flooded before calling this method.
-    fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace<V>, map: &Map) {
+    fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace<V>, map: &Map<'_>) {
         match result {
             ValueOrPlace::Value(value) => self.insert_value_idx(target, value, map),
             ValueOrPlace::Place(source) => self.insert_place_idx(target, source, map),
@@ -581,7 +582,7 @@ impl<V: Clone + HasBottom> State<V> {
     /// This does nothing if the place is not tracked.
     ///
     /// The target place must have been flooded before calling this method.
-    pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) {
+    pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map<'_>) {
         let State::Reachable(values) = self else { return };
         if let Some(value_index) = map.places[target].value_index {
             values.insert(value_index, value)
@@ -595,7 +596,7 @@ impl<V: Clone + HasBottom> State<V> {
     /// places that are non-overlapping or identical.
     ///
     /// The target place must have been flooded before calling this method.
-    pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
+    pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map<'_>) {
         let State::Reachable(values) = self else { return };
 
         // If both places are tracked, we copy the value to the target.
@@ -616,7 +617,7 @@ impl<V: Clone + HasBottom> State<V> {
     }
 
     /// Helper method to interpret `target = result`.
-    pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map)
+    pub fn assign(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map<'_>)
     where
         V: HasTop,
     {
@@ -627,7 +628,7 @@ impl<V: Clone + HasBottom> State<V> {
     }
 
     /// Helper method for assignments to a discriminant.
-    pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map)
+    pub fn assign_discr(&mut self, target: PlaceRef<'_>, result: ValueOrPlace<V>, map: &Map<'_>)
     where
         V: HasTop,
     {
@@ -638,25 +639,25 @@ impl<V: Clone + HasBottom> State<V> {
     }
 
     /// Retrieve the value stored for a place, or `None` if it is not tracked.
-    pub fn try_get(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
+    pub fn try_get(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option<V> {
         let place = map.find(place)?;
         self.try_get_idx(place, map)
     }
 
     /// Retrieve the discriminant stored for a place, or `None` if it is not tracked.
-    pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
+    pub fn try_get_discr(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option<V> {
         let place = map.find_discr(place)?;
         self.try_get_idx(place, map)
     }
 
     /// Retrieve the slice length stored for a place, or `None` if it is not tracked.
-    pub fn try_get_len(&self, place: PlaceRef<'_>, map: &Map) -> Option<V> {
+    pub fn try_get_len(&self, place: PlaceRef<'_>, map: &Map<'_>) -> Option<V> {
         let place = map.find_len(place)?;
         self.try_get_idx(place, map)
     }
 
     /// Retrieve the value stored for a place index, or `None` if it is not tracked.
-    pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option<V> {
+    pub fn try_get_idx(&self, place: PlaceIndex, map: &Map<'_>) -> Option<V> {
         match self {
             State::Reachable(values) => {
                 map.places[place].value_index.map(|v| values.get(v).clone())
@@ -668,7 +669,7 @@ impl<V: Clone + HasBottom> State<V> {
     /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
     ///
     /// This method returns ⊥ if the place is tracked and the state is unreachable.
-    pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V
+    pub fn get(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V
     where
         V: HasBottom + HasTop,
     {
@@ -682,7 +683,7 @@ impl<V: Clone + HasBottom> State<V> {
     /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
     ///
     /// This method returns ⊥ the current state is unreachable.
-    pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V
+    pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V
     where
         V: HasBottom + HasTop,
     {
@@ -696,7 +697,7 @@ impl<V: Clone + HasBottom> State<V> {
     /// Retrieve the value stored for a place, or ⊤ if it is not tracked.
     ///
     /// This method returns ⊥ the current state is unreachable.
-    pub fn get_len(&self, place: PlaceRef<'_>, map: &Map) -> V
+    pub fn get_len(&self, place: PlaceRef<'_>, map: &Map<'_>) -> V
     where
         V: HasBottom + HasTop,
     {
@@ -710,7 +711,7 @@ impl<V: Clone + HasBottom> State<V> {
     /// Retrieve the value stored for a place index, or ⊤ if it is not tracked.
     ///
     /// This method returns ⊥ the current state is unreachable.
-    pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V
+    pub fn get_idx(&self, place: PlaceIndex, map: &Map<'_>) -> V
     where
         V: HasBottom + HasTop,
     {
@@ -746,25 +747,25 @@ impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for State<V> {
 /// - For iteration, every [`PlaceInfo`] contains an intrusive linked list of its children.
 /// - To directly get the child for a specific projection, there is a `projections` map.
 #[derive(Debug)]
-pub struct Map {
+pub struct Map<'tcx> {
     locals: IndexVec<Local, Option<PlaceIndex>>,
     projections: FxHashMap<(PlaceIndex, TrackElem), PlaceIndex>,
-    places: IndexVec<PlaceIndex, PlaceInfo>,
+    places: IndexVec<PlaceIndex, PlaceInfo<'tcx>>,
     value_count: usize,
     // The Range corresponds to a slice into `inner_values_buffer`.
     inner_values: IndexVec<PlaceIndex, Range<usize>>,
     inner_values_buffer: Vec<ValueIndex>,
 }
 
-impl Map {
+impl<'tcx> Map<'tcx> {
     /// Returns a map that only tracks places whose type has scalar layout.
     ///
     /// This is currently the only way to create a [`Map`]. The way in which the tracked places are
     /// chosen is an implementation detail and may not be relied upon (other than that their type
     /// are scalars).
-    pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option<usize>) -> Self {
+    pub fn new(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option<usize>) -> Self {
         let mut map = Self {
-            locals: IndexVec::new(),
+            locals: IndexVec::from_elem(None, &body.local_decls),
             projections: FxHashMap::default(),
             places: IndexVec::new(),
             value_count: 0,
@@ -778,18 +779,15 @@ impl Map {
     }
 
     /// Register all non-excluded places that have scalar layout.
-    fn register<'tcx>(
+    #[tracing::instrument(level = "trace", skip(self, tcx, body))]
+    fn register(
         &mut self,
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
         exclude: BitSet<Local>,
         value_limit: Option<usize>,
     ) {
-        let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len()));
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-
         // Start by constructing the places for each bare local.
-        self.locals = IndexVec::from_elem(None, &body.local_decls);
         for (local, decl) in body.local_decls.iter_enumerated() {
             if exclude.contains(local) {
                 continue;
@@ -797,16 +795,60 @@ impl Map {
 
             // Create a place for the local.
             debug_assert!(self.locals[local].is_none());
-            let place = self.places.push(PlaceInfo::new(None));
+            let place = self.places.push(PlaceInfo::new(decl.ty, None));
             self.locals[local] = Some(place);
+        }
+
+        // Collect syntactic places and assignments between them.
+        let mut collector =
+            PlaceCollector { tcx, body, map: self, assignments: Default::default() };
+        collector.visit_body(body);
+        let PlaceCollector { mut assignments, .. } = collector;
+
+        // Just collecting syntactic places is not enough. We may need to propagate this pattern:
+        //      _1 = (const 5u32, const 13i64);
+        //      _2 = _1;
+        //      _3 = (_2.0 as u32);
+        //
+        // `_1.0` does not appear, but we still need to track it. This is achieved by propagating
+        // projections from assignments. We recorded an assignment between `_2` and `_1`, so we
+        // want `_1` and `_2` to have the same sub-places.
+        //
+        // This is what this fixpoint loop does. While we are still creating places, run through
+        // all the assignments, and register places for children.
+        let mut num_places = 0;
+        while num_places < self.places.len() {
+            num_places = self.places.len();
+
+            for assign in 0.. {
+                let Some(&(lhs, rhs)) = assignments.get_index(assign) else { break };
+
+                // Mirror children from `lhs` in `rhs`.
+                let mut child = self.places[lhs].first_child;
+                while let Some(lhs_child) = child {
+                    let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[lhs_child];
+                    let rhs_child =
+                        self.register_place(ty, rhs, proj_elem.expect("child is not a projection"));
+                    assignments.insert((lhs_child, rhs_child));
+                    child = next_sibling;
+                }
 
-            // And push the eventual children places to the worklist.
-            self.register_children(tcx, param_env, place, decl.ty, &mut worklist);
+                // Conversely, mirror children from `rhs` in `lhs`.
+                let mut child = self.places[rhs].first_child;
+                while let Some(rhs_child) = child {
+                    let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[rhs_child];
+                    let lhs_child =
+                        self.register_place(ty, lhs, proj_elem.expect("child is not a projection"));
+                    assignments.insert((lhs_child, rhs_child));
+                    child = next_sibling;
+                }
+            }
         }
+        drop(assignments);
 
-        // `place.elem1.elem2` with type `ty`.
-        // `elem1` is either `Some(Variant(i))` or `None`.
-        while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() {
+        // Create values for places whose type have scalar layout.
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        for place_info in self.places.iter_mut() {
             // The user requires a bound on the number of created values.
             if let Some(value_limit) = value_limit
                 && self.value_count >= value_limit
@@ -814,19 +856,18 @@ impl Map {
                 break;
             }
 
-            // Create a place for this projection.
-            for elem in [elem1, Some(elem2)].into_iter().flatten() {
-                place = *self.projections.entry((place, elem)).or_insert_with(|| {
-                    // Prepend new child to the linked list.
-                    let next = self.places.push(PlaceInfo::new(Some(elem)));
-                    self.places[next].next_sibling = self.places[place].first_child;
-                    self.places[place].first_child = Some(next);
-                    next
-                });
+            if let Ok(ty) = tcx.try_normalize_erasing_regions(param_env, place_info.ty) {
+                place_info.ty = ty;
             }
 
-            // And push the eventual children places to the worklist.
-            self.register_children(tcx, param_env, place, ty, &mut worklist);
+            // Allocate a value slot if it doesn't have one, and the user requested one.
+            assert!(place_info.value_index.is_none());
+            if let Ok(layout) = tcx.layout_of(param_env.and(place_info.ty))
+                && layout.abi.is_scalar()
+            {
+                place_info.value_index = Some(self.value_count.into());
+                self.value_count += 1;
+            }
         }
 
         // Pre-compute the tree of ValueIndex nested in each PlaceIndex.
@@ -852,68 +893,14 @@ impl Map {
         self.projections.retain(|_, child| !self.inner_values[*child].is_empty());
     }
 
-    /// Potentially register the (local, projection) place and its fields, recursively.
-    ///
-    /// Invariant: The projection must only contain trackable elements.
-    fn register_children<'tcx>(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        place: PlaceIndex,
-        ty: Ty<'tcx>,
-        worklist: &mut VecDeque<(PlaceIndex, Option<TrackElem>, TrackElem, Ty<'tcx>)>,
-    ) {
-        // Allocate a value slot if it doesn't have one, and the user requested one.
-        assert!(self.places[place].value_index.is_none());
-        if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.abi.is_scalar()) {
-            self.places[place].value_index = Some(self.value_count.into());
-            self.value_count += 1;
-        }
-
-        // For enums, directly create the `Discriminant`, as that's their main use.
-        if ty.is_enum() {
-            // Prepend new child to the linked list.
-            let discr = self.places.push(PlaceInfo::new(Some(TrackElem::Discriminant)));
-            self.places[discr].next_sibling = self.places[place].first_child;
-            self.places[place].first_child = Some(discr);
-            let old = self.projections.insert((place, TrackElem::Discriminant), discr);
-            assert!(old.is_none());
-
-            // Allocate a value slot since it doesn't have one.
-            assert!(self.places[discr].value_index.is_none());
-            self.places[discr].value_index = Some(self.value_count.into());
-            self.value_count += 1;
-        }
-
-        if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.kind()
-            && let ty::Slice(..) = ref_ty.kind()
-            // The user may have written a predicate like `[T]: Sized` in their where clauses,
-            // which makes slices scalars.
-            && self.places[place].value_index.is_none()
-        {
-            // Prepend new child to the linked list.
-            let len = self.places.push(PlaceInfo::new(Some(TrackElem::DerefLen)));
-            self.places[len].next_sibling = self.places[place].first_child;
-            self.places[place].first_child = Some(len);
-
-            let old = self.projections.insert((place, TrackElem::DerefLen), len);
-            assert!(old.is_none());
-
-            // Allocate a value slot since it doesn't have one.
-            assert!(self.places[len].value_index.is_none());
-            self.places[len].value_index = Some(self.value_count.into());
-            self.value_count += 1;
-        }
-
-        // Recurse with all fields of this place.
-        iter_fields(ty, tcx, param_env, |variant, field, ty| {
-            worklist.push_back((
-                place,
-                variant.map(TrackElem::Variant),
-                TrackElem::Field(field),
-                ty,
-            ))
-        });
+    #[tracing::instrument(level = "trace", skip(self), ret)]
+    fn register_place(&mut self, ty: Ty<'tcx>, base: PlaceIndex, elem: TrackElem) -> PlaceIndex {
+        *self.projections.entry((base, elem)).or_insert_with(|| {
+            let next = self.places.push(PlaceInfo::new(ty, Some(elem)));
+            self.places[next].next_sibling = self.places[base].first_child;
+            self.places[base].first_child = Some(next);
+            next
+        })
     }
 
     /// Precompute the list of values inside `root` and store it inside
@@ -934,7 +921,108 @@ impl Map {
         let end = self.inner_values_buffer.len();
         self.inner_values[root] = start..end;
     }
+}
+
+struct PlaceCollector<'a, 'b, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    body: &'b Body<'tcx>,
+    map: &'a mut Map<'tcx>,
+    assignments: FxIndexSet<(PlaceIndex, PlaceIndex)>,
+}
+
+impl<'tcx> PlaceCollector<'_, '_, 'tcx> {
+    #[tracing::instrument(level = "trace", skip(self))]
+    fn register_place(&mut self, place: Place<'tcx>) -> Option<PlaceIndex> {
+        // Create a place for this projection.
+        let mut place_index = self.map.locals[place.local]?;
+        let mut ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
+        tracing::trace!(?place_index, ?ty);
+
+        if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind()
+            && let ty::Slice(..) = ref_ty.kind()
+        {
+            self.map.register_place(self.tcx.types.usize, place_index, TrackElem::DerefLen);
+        } else if ty.ty.is_enum() {
+            let discriminant_ty = ty.ty.discriminant_ty(self.tcx);
+            self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant);
+        }
+
+        for proj in place.projection {
+            let track_elem = proj.try_into().ok()?;
+            ty = ty.projection_ty(self.tcx, proj);
+            place_index = self.map.register_place(ty.ty, place_index, track_elem);
+            tracing::trace!(?proj, ?place_index, ?ty);
+
+            if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind()
+                && let ty::Slice(..) = ref_ty.kind()
+            {
+                self.map.register_place(self.tcx.types.usize, place_index, TrackElem::DerefLen);
+            } else if ty.ty.is_enum() {
+                let discriminant_ty = ty.ty.discriminant_ty(self.tcx);
+                self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant);
+            }
+        }
+
+        Some(place_index)
+    }
+}
 
+impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> {
+    #[tracing::instrument(level = "trace", skip(self))]
+    fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, _: Location) {
+        if !ctxt.is_use() {
+            return;
+        }
+
+        self.register_place(*place);
+    }
+
+    fn visit_assign(&mut self, lhs: &Place<'tcx>, rhs: &Rvalue<'tcx>, location: Location) {
+        self.super_assign(lhs, rhs, location);
+
+        match rhs {
+            Rvalue::Use(Operand::Move(rhs) | Operand::Copy(rhs)) | Rvalue::CopyForDeref(rhs) => {
+                let Some(lhs) = self.register_place(*lhs) else { return };
+                let Some(rhs) = self.register_place(*rhs) else { return };
+                self.assignments.insert((lhs, rhs));
+            }
+            Rvalue::Aggregate(kind, fields) => {
+                let Some(mut lhs) = self.register_place(*lhs) else { return };
+                match **kind {
+                    // Do not propagate unions.
+                    AggregateKind::Adt(_, _, _, _, Some(_)) => return,
+                    AggregateKind::Adt(_, variant, _, _, None) => {
+                        let ty = self.map.places[lhs].ty;
+                        if ty.is_enum() {
+                            lhs = self.map.register_place(ty, lhs, TrackElem::Variant(variant));
+                        }
+                    }
+                    AggregateKind::RawPtr(..)
+                    | AggregateKind::Array(_)
+                    | AggregateKind::Tuple
+                    | AggregateKind::Closure(..)
+                    | AggregateKind::Coroutine(..)
+                    | AggregateKind::CoroutineClosure(..) => {}
+                }
+                for (index, field) in fields.iter_enumerated() {
+                    if let Some(rhs) = field.place()
+                        && let Some(rhs) = self.register_place(rhs)
+                    {
+                        let lhs = self.map.register_place(
+                            self.map.places[rhs].ty,
+                            lhs,
+                            TrackElem::Field(index),
+                        );
+                        self.assignments.insert((lhs, rhs));
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+}
+
+impl<'tcx> Map<'tcx> {
     /// Applies a single projection element, yielding the corresponding child.
     pub fn apply(&self, place: PlaceIndex, elem: TrackElem) -> Option<PlaceIndex> {
         self.projections.get(&(place, elem)).copied()
@@ -974,7 +1062,10 @@ impl Map {
     }
 
     /// Iterate over all direct children.
-    fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> + '_ {
+    fn children(
+        &self,
+        parent: PlaceIndex,
+    ) -> impl Iterator<Item = PlaceIndex> + Captures<'_> + Captures<'tcx> {
         Children::new(self, parent)
     }
 
@@ -1081,7 +1172,10 @@ impl Map {
 /// Together, `first_child` and `next_sibling` form an intrusive linked list, which is used to
 /// model a tree structure (a replacement for a member like `children: Vec<PlaceIndex>`).
 #[derive(Debug)]
-struct PlaceInfo {
+struct PlaceInfo<'tcx> {
+    /// Type of the referenced place.
+    ty: Ty<'tcx>,
+
     /// We store a [`ValueIndex`] if and only if the placed is tracked by the analysis.
     value_index: Option<ValueIndex>,
 
@@ -1095,24 +1189,24 @@ struct PlaceInfo {
     next_sibling: Option<PlaceIndex>,
 }
 
-impl PlaceInfo {
-    fn new(proj_elem: Option<TrackElem>) -> Self {
-        Self { next_sibling: None, first_child: None, proj_elem, value_index: None }
+impl<'tcx> PlaceInfo<'tcx> {
+    fn new(ty: Ty<'tcx>, proj_elem: Option<TrackElem>) -> Self {
+        Self { ty, next_sibling: None, first_child: None, proj_elem, value_index: None }
     }
 }
 
-struct Children<'a> {
-    map: &'a Map,
+struct Children<'a, 'tcx> {
+    map: &'a Map<'tcx>,
     next: Option<PlaceIndex>,
 }
 
-impl<'a> Children<'a> {
-    fn new(map: &'a Map, parent: PlaceIndex) -> Self {
+impl<'a, 'tcx> Children<'a, 'tcx> {
+    fn new(map: &'a Map<'tcx>, parent: PlaceIndex) -> Self {
         Self { map, next: map.places[parent].first_child }
     }
 }
 
-impl<'a> Iterator for Children<'a> {
+impl Iterator for Children<'_, '_> {
     type Item = PlaceIndex;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -1261,7 +1355,7 @@ fn debug_with_context_rec<V: Debug + Eq + HasBottom>(
     place_str: &str,
     new: &StateData<V>,
     old: Option<&StateData<V>>,
-    map: &Map,
+    map: &Map<'_>,
     f: &mut Formatter<'_>,
 ) -> std::fmt::Result {
     if let Some(value) = map.places[place].value_index {
@@ -1305,7 +1399,7 @@ fn debug_with_context_rec<V: Debug + Eq + HasBottom>(
 fn debug_with_context<V: Debug + Eq + HasBottom>(
     new: &StateData<V>,
     old: Option<&StateData<V>>,
-    map: &Map,
+    map: &Map<'_>,
     f: &mut Formatter<'_>,
 ) -> std::fmt::Result {
     for (local, place) in map.locals.iter_enumerated() {
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index 25297245172..2ac08ea85d2 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -56,6 +56,10 @@ pub(super) struct MCDCDecision {
 
 #[derive(Default)]
 pub(super) struct ExtractedMappings {
+    /// Store our own copy of [`CoverageGraph::num_nodes`], so that we don't
+    /// need access to the whole graph when allocating per-BCB data. This is
+    /// only public so that other code can still use exhaustive destructuring.
+    pub(super) num_bcbs: usize,
     pub(super) code_mappings: Vec<CodeMapping>,
     pub(super) branch_pairs: Vec<BranchPair>,
     pub(super) mcdc_bitmap_bytes: u32,
@@ -106,6 +110,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
     );
 
     ExtractedMappings {
+        num_bcbs: basic_coverage_blocks.num_nodes(),
         code_mappings,
         branch_pairs,
         mcdc_bitmap_bytes,
@@ -115,12 +120,10 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
 }
 
 impl ExtractedMappings {
-    pub(super) fn all_bcbs_with_counter_mappings(
-        &self,
-        basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set
-    ) -> BitSet<BasicCoverageBlock> {
+    pub(super) fn all_bcbs_with_counter_mappings(&self) -> BitSet<BasicCoverageBlock> {
         // Fully destructure self to make sure we don't miss any fields that have mappings.
         let Self {
+            num_bcbs,
             code_mappings,
             branch_pairs,
             mcdc_bitmap_bytes: _,
@@ -129,7 +132,7 @@ impl ExtractedMappings {
         } = self;
 
         // Identify which BCBs have one or more mappings.
-        let mut bcbs_with_counter_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
+        let mut bcbs_with_counter_mappings = BitSet::new_empty(*num_bcbs);
         let mut insert = |bcb| {
             bcbs_with_counter_mappings.insert(bcb);
         };
@@ -156,6 +159,15 @@ impl ExtractedMappings {
 
         bcbs_with_counter_mappings
     }
+
+    /// Returns the set of BCBs that have one or more `Code` mappings.
+    pub(super) fn bcbs_with_ordinary_code_mappings(&self) -> BitSet<BasicCoverageBlock> {
+        let mut bcbs = BitSet::new_empty(self.num_bcbs);
+        for &CodeMapping { span: _, bcb } in &self.code_mappings {
+            bcbs.insert(bcb);
+        }
+        bcbs
+    }
 }
 
 fn resolve_block_markers(
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 2efca40d180..3772a8f5118 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -25,7 +25,7 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
 
 use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
-use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
+use crate::coverage::graph::CoverageGraph;
 use crate::coverage::mappings::ExtractedMappings;
 use crate::MirPass;
 
@@ -88,8 +88,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
     // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
     // and all `Expression` dependencies (operands) are also generated, for any other
     // `BasicCoverageBlock`s not already associated with a coverage span.
-    let bcbs_with_counter_mappings =
-        extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks);
+    let bcbs_with_counter_mappings = extracted_mappings.all_bcbs_with_counter_mappings();
     if bcbs_with_counter_mappings.is_empty() {
         // No relevant spans were found in MIR, so skip instrumenting this function.
         return;
@@ -109,7 +108,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
     inject_coverage_statements(
         mir_body,
         &basic_coverage_blocks,
-        bcb_has_counter_mappings,
+        &extracted_mappings,
         &coverage_counters,
     );
 
@@ -163,6 +162,7 @@ fn create_mappings<'tcx>(
 
     // Fully destructure the mappings struct to make sure we don't miss any kinds.
     let ExtractedMappings {
+        num_bcbs: _,
         code_mappings,
         branch_pairs,
         mcdc_bitmap_bytes: _,
@@ -219,7 +219,7 @@ fn create_mappings<'tcx>(
 fn inject_coverage_statements<'tcx>(
     mir_body: &mut mir::Body<'tcx>,
     basic_coverage_blocks: &CoverageGraph,
-    bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
+    extracted_mappings: &ExtractedMappings,
     coverage_counters: &CoverageCounters,
 ) {
     // Inject counter-increment statements into MIR.
@@ -252,11 +252,16 @@ fn inject_coverage_statements<'tcx>(
     // can check whether the injected statement survived MIR optimization.
     // (BCB edges can't have spans, so we only need to process BCB nodes here.)
     //
+    // We only do this for ordinary `Code` mappings, because branch and MC/DC
+    // mappings might have expressions that don't correspond to any single
+    // point in the control-flow graph.
+    //
     // See the code in `rustc_codegen_llvm::coverageinfo::map_data` that deals
     // with "expressions seen" and "zero terms".
+    let eligible_bcbs = extracted_mappings.bcbs_with_ordinary_code_mappings();
     for (bcb, expression_id) in coverage_counters
         .bcb_nodes_with_coverage_expressions()
-        .filter(|&(bcb, _)| bcb_has_coverage_spans(bcb))
+        .filter(|&(bcb, _)| eligible_bcbs.contains(bcb))
     {
         inject_statement(
             mir_body,
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 8b965f4d18e..8303ef039d1 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -66,7 +66,7 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
 }
 
 struct ConstAnalysis<'a, 'tcx> {
-    map: Map,
+    map: Map<'tcx>,
     tcx: TyCtxt<'tcx>,
     local_decls: &'a LocalDecls<'tcx>,
     ecx: InterpCx<'tcx, DummyMachine>,
@@ -78,7 +78,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
 
     const NAME: &'static str = "ConstAnalysis";
 
-    fn map(&self) -> &Map {
+    fn map(&self) -> &Map<'tcx> {
         &self.map
     }
 
@@ -330,7 +330,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
 }
 
 impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self {
+    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self {
         let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         Self {
             map,
@@ -560,12 +560,13 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
         Self { patch: Patch::new(tcx), local_decls }
     }
 
+    #[instrument(level = "trace", skip(self, ecx, map), ret)]
     fn try_make_constant(
         &self,
         ecx: &mut InterpCx<'tcx, DummyMachine>,
         place: Place<'tcx>,
         state: &State<FlatSet<Scalar>>,
-        map: &Map,
+        map: &Map<'tcx>,
     ) -> Option<Const<'tcx>> {
         let ty = place.ty(self.local_decls, self.patch.tcx).ty;
         let layout = ecx.layout_of(ty).ok()?;
@@ -598,10 +599,11 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
     }
 }
 
+#[instrument(level = "trace", skip(map), ret)]
 fn propagatable_scalar(
     place: PlaceIndex,
     state: &State<FlatSet<Scalar>>,
-    map: &Map,
+    map: &Map<'_>,
 ) -> Option<Scalar> {
     if let FlatSet::Elem(value) = state.get_idx(place, map)
         && value.try_to_scalar_int().is_ok()
@@ -613,14 +615,14 @@ fn propagatable_scalar(
     }
 }
 
-#[instrument(level = "trace", skip(ecx, state, map))]
+#[instrument(level = "trace", skip(ecx, state, map), ret)]
 fn try_write_constant<'tcx>(
     ecx: &mut InterpCx<'tcx, DummyMachine>,
     dest: &PlaceTy<'tcx>,
     place: PlaceIndex,
     ty: Ty<'tcx>,
     state: &State<FlatSet<Scalar>>,
-    map: &Map,
+    map: &Map<'tcx>,
 ) -> InterpResult<'tcx> {
     let layout = ecx.layout_of(ty)?;
 
@@ -719,6 +721,7 @@ impl<'mir, 'tcx>
 {
     type FlowState = State<FlatSet<Scalar>>;
 
+    #[instrument(level = "trace", skip(self, results, statement))]
     fn visit_statement_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
@@ -740,6 +743,7 @@ impl<'mir, 'tcx>
         }
     }
 
+    #[instrument(level = "trace", skip(self, results, statement))]
     fn visit_statement_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
@@ -834,7 +838,7 @@ struct OperandCollector<'tcx, 'map, 'locals, 'a> {
     state: &'a State<FlatSet<Scalar>>,
     visitor: &'a mut Collector<'tcx, 'locals>,
     ecx: &'map mut InterpCx<'tcx, DummyMachine>,
-    map: &'map Map,
+    map: &'map Map<'tcx>,
 }
 
 impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 97ec0cb39de..2100f4b4a1a 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -123,7 +123,7 @@ struct TOFinder<'tcx, 'a> {
     param_env: ty::ParamEnv<'tcx>,
     ecx: InterpCx<'tcx, DummyMachine>,
     body: &'a Body<'tcx>,
-    map: &'a Map,
+    map: &'a Map<'tcx>,
     loop_headers: &'a BitSet<BasicBlock>,
     /// We use an arena to avoid cloning the slices when cloning `state`.
     arena: &'a DroplessArena,
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index c90f8e76163..c23bc8f09ad 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -16,9 +16,9 @@ use crate::delegate::SolverDelegate;
 use crate::solve::inspect::{self, ProofTreeBuilder};
 use crate::solve::search_graph::SearchGraph;
 use crate::solve::{
-    search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind,
-    GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData,
-    QueryResult, SolverMode, FIXPOINT_STEP_LIMIT,
+    CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource, MaybeCause,
+    NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, SolverMode,
+    FIXPOINT_STEP_LIMIT,
 };
 
 pub(super) mod canonical;
@@ -72,7 +72,7 @@ where
     /// new placeholders to the caller.
     pub(super) max_input_universe: ty::UniverseIndex,
 
-    pub(super) search_graph: &'a mut SearchGraph<I>,
+    pub(super) search_graph: &'a mut SearchGraph<D>,
 
     nested_goals: NestedGoals<I>,
 
@@ -200,7 +200,7 @@ where
         generate_proof_tree: GenerateProofTree,
         f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
     ) -> (R, Option<inspect::GoalEvaluation<I>>) {
-        let mut search_graph = search_graph::SearchGraph::new(delegate.solver_mode());
+        let mut search_graph = SearchGraph::new(delegate.solver_mode());
 
         let mut ecx = EvalCtxt {
             delegate,
@@ -241,7 +241,7 @@ where
     /// and registering opaques from the canonicalized input.
     fn enter_canonical<R>(
         cx: I,
-        search_graph: &'a mut search_graph::SearchGraph<I>,
+        search_graph: &'a mut SearchGraph<D>,
         canonical_input: CanonicalInput<I>,
         canonical_goal_evaluation: &mut ProofTreeBuilder<D>,
         f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
@@ -296,7 +296,7 @@ where
     #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)]
     fn evaluate_canonical_goal(
         cx: I,
-        search_graph: &'a mut search_graph::SearchGraph<I>,
+        search_graph: &'a mut SearchGraph<D>,
         canonical_input: CanonicalInput<I>,
         goal_evaluation: &mut ProofTreeBuilder<D>,
     ) -> QueryResult<I> {
diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
index b50676e8d53..3e266ddac71 100644
--- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
@@ -8,7 +8,7 @@ use std::marker::PhantomData;
 use std::mem;
 
 use rustc_type_ir::inherent::*;
-use rustc_type_ir::{self as ty, Interner};
+use rustc_type_ir::{self as ty, search_graph, Interner};
 
 use crate::delegate::SolverDelegate;
 use crate::solve::eval_ctxt::canonical;
@@ -38,7 +38,7 @@ use crate::solve::{
 /// trees. At the end of trait solving `ProofTreeBuilder::finalize`
 /// is called to recursively convert the whole structure to a
 /// finished proof tree.
-pub(in crate::solve) struct ProofTreeBuilder<D, I = <D as SolverDelegate>::Interner>
+pub(crate) struct ProofTreeBuilder<D, I = <D as SolverDelegate>::Interner>
 where
     D: SolverDelegate<Interner = I>,
     I: Interner,
@@ -321,23 +321,6 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
         })
     }
 
-    pub fn finalize_canonical_goal_evaluation(
-        &mut self,
-        cx: I,
-    ) -> Option<I::CanonicalGoalEvaluationStepRef> {
-        self.as_mut().map(|this| match this {
-            DebugSolver::CanonicalGoalEvaluation(evaluation) => {
-                let final_revision = mem::take(&mut evaluation.final_revision).unwrap();
-                let final_revision =
-                    cx.intern_canonical_goal_evaluation_step(final_revision.finalize());
-                let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision };
-                assert_eq!(evaluation.kind.replace(kind), None);
-                final_revision
-            }
-            _ => unreachable!(),
-        })
-    }
-
     pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<D>) {
         if let Some(this) = self.as_mut() {
             match (this, *canonical_goal_evaluation.state.unwrap()) {
@@ -571,3 +554,51 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
         }
     }
 }
+
+impl<D, I> search_graph::ProofTreeBuilder<I> for ProofTreeBuilder<D>
+where
+    D: SolverDelegate<Interner = I>,
+    I: Interner,
+{
+    fn try_apply_proof_tree(
+        &mut self,
+        proof_tree: Option<I::CanonicalGoalEvaluationStepRef>,
+    ) -> bool {
+        if !self.is_noop() {
+            if let Some(final_revision) = proof_tree {
+                let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision };
+                self.canonical_goal_evaluation_kind(kind);
+                true
+            } else {
+                false
+            }
+        } else {
+            true
+        }
+    }
+
+    fn on_provisional_cache_hit(&mut self) {
+        self.canonical_goal_evaluation_kind(WipCanonicalGoalEvaluationKind::ProvisionalCacheHit);
+    }
+
+    fn on_cycle_in_stack(&mut self) {
+        self.canonical_goal_evaluation_kind(WipCanonicalGoalEvaluationKind::CycleInStack);
+    }
+
+    fn finalize_canonical_goal_evaluation(
+        &mut self,
+        tcx: I,
+    ) -> Option<I::CanonicalGoalEvaluationStepRef> {
+        self.as_mut().map(|this| match this {
+            DebugSolver::CanonicalGoalEvaluation(evaluation) => {
+                let final_revision = mem::take(&mut evaluation.final_revision).unwrap();
+                let final_revision =
+                    tcx.intern_canonical_goal_evaluation_step(final_revision.finalize());
+                let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision };
+                assert_eq!(evaluation.kind.replace(kind), None);
+                final_revision
+            }
+            _ => unreachable!(),
+        })
+    }
+}
diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
index 69d52dcad7a..fe053a506e7 100644
--- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
@@ -1,599 +1,90 @@
-use std::mem;
+use std::marker::PhantomData;
 
-use rustc_index::{Idx, IndexVec};
-use rustc_type_ir::data_structures::{HashMap, HashSet};
 use rustc_type_ir::inherent::*;
+use rustc_type_ir::search_graph::{self, CycleKind, UsageKind};
+use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult};
 use rustc_type_ir::Interner;
-use tracing::debug;
 
+use super::inspect::{self, ProofTreeBuilder};
+use super::FIXPOINT_STEP_LIMIT;
 use crate::delegate::SolverDelegate;
-use crate::solve::inspect::{self, ProofTreeBuilder};
-use crate::solve::{
-    CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT,
-};
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct SolverLimit(usize);
-
-rustc_index::newtype_index! {
-    #[orderable]
-    #[gate_rustc_only]
-    pub struct StackDepth {}
-}
-
-bitflags::bitflags! {
-    /// Whether and how this goal has been used as the root of a
-    /// cycle. We track the kind of cycle as we're otherwise forced
-    /// to always rerun at least once.
-    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
-    struct HasBeenUsed: u8 {
-        const INDUCTIVE_CYCLE = 1 << 0;
-        const COINDUCTIVE_CYCLE = 1 << 1;
-    }
-}
-
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""))]
-struct StackEntry<I: Interner> {
-    input: CanonicalInput<I>,
-
-    available_depth: SolverLimit,
-
-    /// The maximum depth reached by this stack entry, only up-to date
-    /// for the top of the stack and lazily updated for the rest.
-    reached_depth: StackDepth,
-
-    /// Whether this entry is a non-root cycle participant.
-    ///
-    /// We must not move the result of non-root cycle participants to the
-    /// global cache. We store the highest stack depth of a head of a cycle
-    /// this goal is involved in. This necessary to soundly cache its
-    /// provisional result.
-    non_root_cycle_participant: Option<StackDepth>,
-
-    encountered_overflow: bool,
-
-    has_been_used: HasBeenUsed,
-
-    /// We put only the root goal of a coinductive cycle into the global cache.
-    ///
-    /// If we were to use that result when later trying to prove another cycle
-    /// participant, we can end up with unstable query results.
-    ///
-    /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
-    /// an example of where this is needed.
-    ///
-    /// There can  be multiple roots on the same stack, so we need to track
-    /// cycle participants per root:
-    /// ```plain
-    /// A :- B
-    /// B :- A, C
-    /// C :- D
-    /// D :- C
-    /// ```
-    nested_goals: HashSet<CanonicalInput<I>>,
-    /// Starts out as `None` and gets set when rerunning this
-    /// goal in case we encounter a cycle.
-    provisional_result: Option<QueryResult<I>>,
-}
-
-/// The provisional result for a goal which is not on the stack.
-#[derive(Debug)]
-struct DetachedEntry<I: Interner> {
-    /// The head of the smallest non-trivial cycle involving this entry.
-    ///
-    /// Given the following rules, when proving `A` the head for
-    /// the provisional entry of `C` would be `B`.
-    /// ```plain
-    /// A :- B
-    /// B :- C
-    /// C :- A + B + C
-    /// ```
-    head: StackDepth,
-    result: QueryResult<I>,
-}
-
-/// Stores the stack depth of a currently evaluated goal *and* already
-/// computed results for goals which depend on other goals still on the stack.
-///
-/// The provisional result may depend on whether the stack above it is inductive
-/// or coinductive. Because of this, we store separate provisional results for
-/// each case. If an provisional entry is not applicable, it may be the case
-/// that we already have provisional result while computing a goal. In this case
-/// we prefer the provisional result to potentially avoid fixpoint iterations.
-/// See tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs for an example.
-///
-/// The provisional cache can theoretically result in changes to the observable behavior,
-/// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs.
-#[derive(derivative::Derivative)]
-#[derivative(Default(bound = ""))]
-struct ProvisionalCacheEntry<I: Interner> {
-    stack_depth: Option<StackDepth>,
-    with_inductive_stack: Option<DetachedEntry<I>>,
-    with_coinductive_stack: Option<DetachedEntry<I>>,
-}
-
-impl<I: Interner> ProvisionalCacheEntry<I> {
-    fn is_empty(&self) -> bool {
-        self.stack_depth.is_none()
-            && self.with_inductive_stack.is_none()
-            && self.with_coinductive_stack.is_none()
-    }
+/// This type is never constructed. We only use it to implement `search_graph::Delegate`
+/// for all types which impl `SolverDelegate` and doing it directly fails in coherence.
+pub(super) struct SearchGraphDelegate<D: SolverDelegate> {
+    _marker: PhantomData<D>,
 }
+pub(super) type SearchGraph<D> = search_graph::SearchGraph<SearchGraphDelegate<D>>;
+impl<D, I> search_graph::Delegate for SearchGraphDelegate<D>
+where
+    D: SolverDelegate<Interner = I>,
+    I: Interner,
+{
+    type Cx = D::Interner;
 
-pub(super) struct SearchGraph<I: Interner> {
-    mode: SolverMode,
-    /// The stack of goals currently being computed.
-    ///
-    /// An element is *deeper* in the stack if its index is *lower*.
-    stack: IndexVec<StackDepth, StackEntry<I>>,
-    provisional_cache: HashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>,
-}
+    const FIXPOINT_STEP_LIMIT: usize = FIXPOINT_STEP_LIMIT;
 
-impl<I: Interner> SearchGraph<I> {
-    pub(super) fn new(mode: SolverMode) -> SearchGraph<I> {
-        Self { mode, stack: Default::default(), provisional_cache: Default::default() }
-    }
+    type ProofTreeBuilder = ProofTreeBuilder<D>;
 
-    pub(super) fn solver_mode(&self) -> SolverMode {
-        self.mode
+    fn recursion_limit(cx: I) -> usize {
+        cx.recursion_limit()
     }
 
-    fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) {
-        if let Some(parent) = self.stack.raw.last_mut() {
-            parent.reached_depth = parent.reached_depth.max(reached_depth);
-            parent.encountered_overflow |= encountered_overflow;
-        }
-    }
-
-    pub(super) fn is_empty(&self) -> bool {
-        self.stack.is_empty()
-    }
-
-    /// Returns the remaining depth allowed for nested goals.
-    ///
-    /// This is generally simply one less than the current depth.
-    /// However, if we encountered overflow, we significantly reduce
-    /// the remaining depth of all nested goals to prevent hangs
-    /// in case there is exponential blowup.
-    fn allowed_depth_for_nested(
+    fn initial_provisional_result(
         cx: I,
-        stack: &IndexVec<StackDepth, StackEntry<I>>,
-    ) -> Option<SolverLimit> {
-        if let Some(last) = stack.raw.last() {
-            if last.available_depth.0 == 0 {
-                return None;
-            }
-
-            Some(if last.encountered_overflow {
-                SolverLimit(last.available_depth.0 / 4)
-            } else {
-                SolverLimit(last.available_depth.0 - 1)
-            })
-        } else {
-            Some(SolverLimit(cx.recursion_limit()))
-        }
-    }
-
-    fn stack_coinductive_from(
-        cx: I,
-        stack: &IndexVec<StackDepth, StackEntry<I>>,
-        head: StackDepth,
-    ) -> bool {
-        stack.raw[head.index()..]
-            .iter()
-            .all(|entry| entry.input.value.goal.predicate.is_coinductive(cx))
-    }
-
-    // When encountering a solver cycle, the result of the current goal
-    // depends on goals lower on the stack.
-    //
-    // We have to therefore be careful when caching goals. Only the final result
-    // of the cycle root, i.e. the lowest goal on the stack involved in this cycle,
-    // is moved to the global cache while all others are stored in a provisional cache.
-    //
-    // We update both the head of this cycle to rerun its evaluation until
-    // we reach a fixpoint and all other cycle participants to make sure that
-    // their result does not get moved to the global cache.
-    fn tag_cycle_participants(
-        stack: &mut IndexVec<StackDepth, StackEntry<I>>,
-        usage_kind: HasBeenUsed,
-        head: StackDepth,
-    ) {
-        stack[head].has_been_used |= usage_kind;
-        debug_assert!(!stack[head].has_been_used.is_empty());
-
-        // The current root of these cycles. Note that this may not be the final
-        // root in case a later goal depends on a goal higher up the stack.
-        let mut current_root = head;
-        while let Some(parent) = stack[current_root].non_root_cycle_participant {
-            current_root = parent;
-            debug_assert!(!stack[current_root].has_been_used.is_empty());
-        }
-
-        let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1);
-        let current_cycle_root = &mut stack[current_root.as_usize()];
-        for entry in cycle_participants {
-            entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head));
-            current_cycle_root.nested_goals.insert(entry.input);
-            current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals));
+        kind: CycleKind,
+        input: CanonicalInput<I>,
+    ) -> QueryResult<I> {
+        match kind {
+            CycleKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes),
+            CycleKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)),
         }
     }
 
-    fn clear_dependent_provisional_results(
-        provisional_cache: &mut HashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>,
-        head: StackDepth,
-    ) {
-        #[allow(rustc::potential_query_instability)]
-        provisional_cache.retain(|_, entry| {
-            if entry.with_coinductive_stack.as_ref().is_some_and(|p| p.head == head) {
-                entry.with_coinductive_stack.take();
-            }
-            if entry.with_inductive_stack.as_ref().is_some_and(|p| p.head == head) {
-                entry.with_inductive_stack.take();
-            }
-            !entry.is_empty()
-        });
-    }
-
-    /// The trait solver behavior is different for coherence
-    /// so we use a separate cache. Alternatively we could use
-    /// a single cache and share it between coherence and ordinary
-    /// trait solving.
-    pub(super) fn global_cache(&self, cx: I) -> I::EvaluationCache {
-        cx.evaluation_cache(self.mode)
-    }
-
-    /// Probably the most involved method of the whole solver.
-    ///
-    /// Given some goal which is proven via the `prove_goal` closure, this
-    /// handles caching, overflow, and coinductive cycles.
-    pub(super) fn with_new_goal<D: SolverDelegate<Interner = I>>(
-        &mut self,
+    fn reached_fixpoint(
         cx: I,
+        kind: UsageKind,
         input: CanonicalInput<I>,
-        inspect: &mut ProofTreeBuilder<D>,
-        mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<D>) -> QueryResult<I>,
-    ) -> QueryResult<I> {
-        self.check_invariants();
-        // Check for overflow.
-        let Some(available_depth) = Self::allowed_depth_for_nested(cx, &self.stack) else {
-            if let Some(last) = self.stack.raw.last_mut() {
-                last.encountered_overflow = true;
-            }
-
-            inspect
-                .canonical_goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow);
-            return Self::response_no_constraints(cx, input, Certainty::overflow(true));
-        };
-
-        if let Some(result) = self.lookup_global_cache(cx, input, available_depth, inspect) {
-            debug!("global cache hit");
-            return result;
-        }
-
-        // Check whether the goal is in the provisional cache.
-        // The provisional result may rely on the path to its cycle roots,
-        // so we have to check the path of the current goal matches that of
-        // the cache entry.
-        let cache_entry = self.provisional_cache.entry(input).or_default();
-        if let Some(entry) = cache_entry
-            .with_coinductive_stack
-            .as_ref()
-            .filter(|p| Self::stack_coinductive_from(cx, &self.stack, p.head))
-            .or_else(|| {
-                cache_entry
-                    .with_inductive_stack
-                    .as_ref()
-                    .filter(|p| !Self::stack_coinductive_from(cx, &self.stack, p.head))
-            })
-        {
-            debug!("provisional cache hit");
-            // We have a nested goal which is already in the provisional cache, use
-            // its result. We do not provide any usage kind as that should have been
-            // already set correctly while computing the cache entry.
-            inspect.canonical_goal_evaluation_kind(
-                inspect::WipCanonicalGoalEvaluationKind::ProvisionalCacheHit,
-            );
-            Self::tag_cycle_participants(&mut self.stack, HasBeenUsed::empty(), entry.head);
-            return entry.result;
-        } else if let Some(stack_depth) = cache_entry.stack_depth {
-            debug!("encountered cycle with depth {stack_depth:?}");
-            // We have a nested goal which directly relies on a goal deeper in the stack.
-            //
-            // We start by tagging all cycle participants, as that's necessary for caching.
-            //
-            // Finally we can return either the provisional response or the initial response
-            // in case we're in the first fixpoint iteration for this goal.
-            inspect.canonical_goal_evaluation_kind(
-                inspect::WipCanonicalGoalEvaluationKind::CycleInStack,
-            );
-            let is_coinductive_cycle = Self::stack_coinductive_from(cx, &self.stack, stack_depth);
-            let usage_kind = if is_coinductive_cycle {
-                HasBeenUsed::COINDUCTIVE_CYCLE
-            } else {
-                HasBeenUsed::INDUCTIVE_CYCLE
-            };
-            Self::tag_cycle_participants(&mut self.stack, usage_kind, stack_depth);
-
-            // Return the provisional result or, if we're in the first iteration,
-            // start with no constraints.
-            return if let Some(result) = self.stack[stack_depth].provisional_result {
-                result
-            } else if is_coinductive_cycle {
-                Self::response_no_constraints(cx, input, Certainty::Yes)
-            } else {
-                Self::response_no_constraints(cx, input, Certainty::overflow(false))
-            };
+        provisional_result: Option<QueryResult<I>>,
+        result: QueryResult<I>,
+    ) -> bool {
+        if let Some(r) = provisional_result {
+            r == result
         } else {
-            // No entry, we push this goal on the stack and try to prove it.
-            let depth = self.stack.next_index();
-            let entry = StackEntry {
-                input,
-                available_depth,
-                reached_depth: depth,
-                non_root_cycle_participant: None,
-                encountered_overflow: false,
-                has_been_used: HasBeenUsed::empty(),
-                nested_goals: Default::default(),
-                provisional_result: None,
-            };
-            assert_eq!(self.stack.push(entry), depth);
-            cache_entry.stack_depth = Some(depth);
-        }
-
-        // This is for global caching, so we properly track query dependencies.
-        // Everything that affects the `result` should be performed within this
-        // `with_anon_task` closure. If computing this goal depends on something
-        // not tracked by the cache key and from outside of this anon task, it
-        // must not be added to the global cache. Notably, this is the case for
-        // trait solver cycles participants.
-        let ((final_entry, result), dep_node) = cx.with_cached_task(|| {
-            for _ in 0..FIXPOINT_STEP_LIMIT {
-                match self.fixpoint_step_in_task(cx, input, inspect, &mut prove_goal) {
-                    StepResult::Done(final_entry, result) => return (final_entry, result),
-                    StepResult::HasChanged => debug!("fixpoint changed provisional results"),
+            match kind {
+                UsageKind::Single(CycleKind::Coinductive) => {
+                    response_no_constraints(cx, input, Certainty::Yes) == result
                 }
+                UsageKind::Single(CycleKind::Inductive) => {
+                    response_no_constraints(cx, input, Certainty::overflow(false)) == result
+                }
+                UsageKind::Mixed => false,
             }
-
-            debug!("canonical cycle overflow");
-            let current_entry = self.stack.pop().unwrap();
-            debug_assert!(current_entry.has_been_used.is_empty());
-            let result = Self::response_no_constraints(cx, input, Certainty::overflow(false));
-            (current_entry, result)
-        });
-
-        let proof_tree = inspect.finalize_canonical_goal_evaluation(cx);
-
-        self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow);
-
-        // We're now done with this goal. In case this goal is involved in a larger cycle
-        // do not remove it from the provisional cache and update its provisional result.
-        // We only add the root of cycles to the global cache.
-        if let Some(head) = final_entry.non_root_cycle_participant {
-            let coinductive_stack = Self::stack_coinductive_from(cx, &self.stack, head);
-
-            let entry = self.provisional_cache.get_mut(&input).unwrap();
-            entry.stack_depth = None;
-            if coinductive_stack {
-                entry.with_coinductive_stack = Some(DetachedEntry { head, result });
-            } else {
-                entry.with_inductive_stack = Some(DetachedEntry { head, result });
-            }
-        } else {
-            self.provisional_cache.remove(&input);
-            let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len();
-            // When encountering a cycle, both inductive and coinductive, we only
-            // move the root into the global cache. We also store all other cycle
-            // participants involved.
-            //
-            // We must not use the global cache entry of a root goal if a cycle
-            // participant is on the stack. This is necessary to prevent unstable
-            // results. See the comment of `StackEntry::nested_goals` for
-            // more details.
-            self.global_cache(cx).insert(
-                cx,
-                input,
-                proof_tree,
-                reached_depth,
-                final_entry.encountered_overflow,
-                final_entry.nested_goals,
-                dep_node,
-                result,
-            )
         }
-
-        self.check_invariants();
-
-        result
     }
 
-    /// Try to fetch a previously computed result from the global cache,
-    /// making sure to only do so if it would match the result of reevaluating
-    /// this goal.
-    fn lookup_global_cache<D: SolverDelegate<Interner = I>>(
-        &mut self,
+    fn on_stack_overflow(
         cx: I,
-        input: CanonicalInput<I>,
-        available_depth: SolverLimit,
         inspect: &mut ProofTreeBuilder<D>,
-    ) -> Option<QueryResult<I>> {
-        let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self
-            .global_cache(cx)
-            // FIXME: Awkward `Limit -> usize -> Limit`.
-            .get(cx, input, self.stack.iter().map(|e| e.input), available_depth.0)?;
-
-        // If we're building a proof tree and the current cache entry does not
-        // contain a proof tree, we do not use the entry but instead recompute
-        // the goal. We simply overwrite the existing entry once we're done,
-        // caching the proof tree.
-        if !inspect.is_noop() {
-            if let Some(final_revision) = proof_tree {
-                let kind = inspect::WipCanonicalGoalEvaluationKind::Interned { final_revision };
-                inspect.canonical_goal_evaluation_kind(kind);
-            } else {
-                return None;
-            }
-        }
-
-        // Adjust the parent goal as if we actually computed this goal.
-        let reached_depth = self.stack.next_index().plus(additional_depth);
-        self.update_parent_goal(reached_depth, encountered_overflow);
-
-        Some(result)
-    }
-}
-
-enum StepResult<I: Interner> {
-    Done(StackEntry<I>, QueryResult<I>),
-    HasChanged,
-}
-
-impl<I: Interner> SearchGraph<I> {
-    /// When we encounter a coinductive cycle, we have to fetch the
-    /// result of that cycle while we are still computing it. Because
-    /// of this we continuously recompute the cycle until the result
-    /// of the previous iteration is equal to the final result, at which
-    /// point we are done.
-    fn fixpoint_step_in_task<D, F>(
-        &mut self,
-        cx: I,
         input: CanonicalInput<I>,
-        inspect: &mut ProofTreeBuilder<D>,
-        prove_goal: &mut F,
-    ) -> StepResult<I>
-    where
-        D: SolverDelegate<Interner = I>,
-        F: FnMut(&mut Self, &mut ProofTreeBuilder<D>) -> QueryResult<I>,
-    {
-        let result = prove_goal(self, inspect);
-        let stack_entry = self.stack.pop().unwrap();
-        debug_assert_eq!(stack_entry.input, input);
-
-        // If the current goal is not the root of a cycle, we are done.
-        if stack_entry.has_been_used.is_empty() {
-            return StepResult::Done(stack_entry, result);
-        }
-
-        // If it is a cycle head, we have to keep trying to prove it until
-        // we reach a fixpoint. We need to do so for all cycle heads,
-        // not only for the root.
-        //
-        // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
-        // for an example.
-
-        // Start by clearing all provisional cache entries which depend on this
-        // the current goal.
-        Self::clear_dependent_provisional_results(
-            &mut self.provisional_cache,
-            self.stack.next_index(),
-        );
-
-        // Check whether we reached a fixpoint, either because the final result
-        // is equal to the provisional result of the previous iteration, or because
-        // this was only the root of either coinductive or inductive cycles, and the
-        // final result is equal to the initial response for that case.
-        let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
-            r == result
-        } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
-            Self::response_no_constraints(cx, input, Certainty::Yes) == result
-        } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
-            Self::response_no_constraints(cx, input, Certainty::overflow(false)) == result
-        } else {
-            false
-        };
-
-        // If we did not reach a fixpoint, update the provisional result and reevaluate.
-        if reached_fixpoint {
-            StepResult::Done(stack_entry, result)
-        } else {
-            let depth = self.stack.push(StackEntry {
-                has_been_used: HasBeenUsed::empty(),
-                provisional_result: Some(result),
-                ..stack_entry
-            });
-            debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
-            StepResult::HasChanged
-        }
-    }
-
-    fn response_no_constraints(
-        cx: I,
-        goal: CanonicalInput<I>,
-        certainty: Certainty,
     ) -> QueryResult<I> {
-        Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty))
+        inspect.canonical_goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow);
+        response_no_constraints(cx, input, Certainty::overflow(true))
     }
 
-    #[allow(rustc::potential_query_instability)]
-    fn check_invariants(&self) {
-        if !cfg!(debug_assertions) {
-            return;
-        }
-
-        let SearchGraph { mode: _, stack, provisional_cache } = self;
-        if stack.is_empty() {
-            assert!(provisional_cache.is_empty());
-        }
-
-        for (depth, entry) in stack.iter_enumerated() {
-            let StackEntry {
-                input,
-                available_depth: _,
-                reached_depth: _,
-                non_root_cycle_participant,
-                encountered_overflow: _,
-                has_been_used,
-                ref nested_goals,
-                provisional_result,
-            } = *entry;
-            let cache_entry = provisional_cache.get(&entry.input).unwrap();
-            assert_eq!(cache_entry.stack_depth, Some(depth));
-            if let Some(head) = non_root_cycle_participant {
-                assert!(head < depth);
-                assert!(nested_goals.is_empty());
-                assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
-
-                let mut current_root = head;
-                while let Some(parent) = stack[current_root].non_root_cycle_participant {
-                    current_root = parent;
-                }
-                assert!(stack[current_root].nested_goals.contains(&input));
-            }
-
-            if !nested_goals.is_empty() {
-                assert!(provisional_result.is_some() || !has_been_used.is_empty());
-                for entry in stack.iter().take(depth.as_usize()) {
-                    assert_eq!(nested_goals.get(&entry.input), None);
-                }
-            }
-        }
-
-        for (&input, entry) in &self.provisional_cache {
-            let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } =
-                entry;
-            assert!(
-                stack_depth.is_some()
-                    || with_coinductive_stack.is_some()
-                    || with_inductive_stack.is_some()
-            );
-
-            if let &Some(stack_depth) = stack_depth {
-                assert_eq!(stack[stack_depth].input, input);
-            }
-
-            let check_detached = |detached_entry: &DetachedEntry<I>| {
-                let DetachedEntry { head, result: _ } = *detached_entry;
-                assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
-            };
-
-            if let Some(with_coinductive_stack) = with_coinductive_stack {
-                check_detached(with_coinductive_stack);
-            }
+    fn on_fixpoint_overflow(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
+        response_no_constraints(cx, input, Certainty::overflow(false))
+    }
 
-            if let Some(with_inductive_stack) = with_inductive_stack {
-                check_detached(with_inductive_stack);
-            }
-        }
+    fn step_is_coinductive(cx: I, input: CanonicalInput<I>) -> bool {
+        input.value.goal.predicate.is_coinductive(cx)
     }
 }
+
+fn response_no_constraints<I: Interner>(
+    cx: I,
+    goal: CanonicalInput<I>,
+    certainty: Certainty,
+) -> QueryResult<I> {
+    Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty))
+}
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 02c3c87313b..c2201b1c41e 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -1,7 +1,7 @@
 parse_add_paren = try adding parentheses
 
 parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
-    .suggestion = add parentheses to clarify the precedence
+parse_ambiguous_range_pattern_suggestion = add parentheses to clarify the precedence
 
 parse_array_brackets_instead_of_braces = this is a block expression, not an array
     .suggestion = to make an array, use square brackets instead of curly braces
@@ -323,10 +323,10 @@ parse_incorrect_semicolon =
     .suggestion = remove this semicolon
     .help = {$name} declarations are not followed by a semicolon
 
-parse_incorrect_use_of_await =
-    incorrect use of `await`
+parse_incorrect_use_of_await = incorrect use of `await`
     .parentheses_suggestion = `await` is not a method call, remove the parentheses
-    .postfix_suggestion = `await` is a postfix operation
+
+parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation
 
 parse_incorrect_visibility_restriction = incorrect visibility restriction
     .help = some possible visibility restrictions are:
@@ -644,7 +644,7 @@ parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call
     .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
 
 parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
-    .suggestion = remove the parentheses
+parse_parenthesized_lifetime_suggestion = remove the parentheses
 
 parse_path_single_colon = path separator must be a double colon
     .suggestion = use a double colon instead
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 3ae9b6dad99..092a2a10ab7 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -18,10 +18,10 @@ use crate::parser::{ForbiddenLetReason, TokenDescription};
 #[derive(Diagnostic)]
 #[diag(parse_maybe_report_ambiguous_plus)]
 pub(crate) struct AmbiguousPlus {
-    pub sum_ty: String,
     #[primary_span]
-    #[suggestion(code = "({sum_ty})")]
     pub span: Span,
+    #[subdiagnostic]
+    pub suggestion: AddParen,
 }
 
 #[derive(Diagnostic)]
@@ -35,16 +35,19 @@ pub(crate) struct BadTypePlus {
 }
 
 #[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")]
+pub(crate) struct AddParen {
+    #[suggestion_part(code = "(")]
+    pub lo: Span,
+    #[suggestion_part(code = ")")]
+    pub hi: Span,
+}
+
+#[derive(Subdiagnostic)]
 pub(crate) enum BadTypePlusSub {
-    #[suggestion(
-        parse_add_paren,
-        code = "{sum_with_parens}",
-        applicability = "machine-applicable"
-    )]
     AddParen {
-        sum_with_parens: String,
-        #[primary_span]
-        span: Span,
+        #[subdiagnostic]
+        suggestion: AddParen,
     },
     #[label(parse_forgot_paren)]
     ForgotParen {
@@ -80,7 +83,7 @@ pub(crate) struct WrapType {
 #[diag(parse_incorrect_semicolon)]
 pub(crate) struct IncorrectSemicolon<'a> {
     #[primary_span]
-    #[suggestion(style = "short", code = "", applicability = "machine-applicable")]
+    #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
     pub span: Span,
     #[help]
     pub show_help: bool,
@@ -91,19 +94,35 @@ pub(crate) struct IncorrectSemicolon<'a> {
 #[diag(parse_incorrect_use_of_await)]
 pub(crate) struct IncorrectUseOfAwait {
     #[primary_span]
-    #[suggestion(parse_parentheses_suggestion, code = "", applicability = "machine-applicable")]
+    #[suggestion(
+        parse_parentheses_suggestion,
+        style = "verbose",
+        code = "",
+        applicability = "machine-applicable"
+    )]
     pub span: Span,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    parse_incorrect_use_of_await_postfix_suggestion,
+    applicability = "machine-applicable"
+)]
+pub(crate) struct AwaitSuggestion {
+    #[suggestion_part(code = "")]
+    pub removal: Span,
+    #[suggestion_part(code = ".await{question_mark}")]
+    pub dot_await: Span,
+    pub question_mark: &'static str,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_incorrect_use_of_await)]
 pub(crate) struct IncorrectAwait {
     #[primary_span]
     pub span: Span,
-    #[suggestion(parse_postfix_suggestion, code = "{expr}.await{question_mark}")]
-    pub sugg_span: (Span, Applicability),
-    pub expr: String,
-    pub question_mark: &'static str,
+    #[subdiagnostic]
+    pub suggestion: AwaitSuggestion,
 }
 
 #[derive(Diagnostic)]
@@ -111,7 +130,7 @@ pub(crate) struct IncorrectAwait {
 pub(crate) struct InInTypo {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", style = "verbose", applicability = "machine-applicable")]
     pub sugg_span: Span,
 }
 
@@ -126,17 +145,33 @@ pub(crate) struct InvalidVariableDeclaration {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidVariableDeclarationSub {
-    #[suggestion(parse_switch_mut_let_order, applicability = "maybe-incorrect", code = "let mut")]
+    #[suggestion(
+        parse_switch_mut_let_order,
+        style = "verbose",
+        applicability = "maybe-incorrect",
+        code = "let mut"
+    )]
     SwitchMutLetOrder(#[primary_span] Span),
     #[suggestion(
         parse_missing_let_before_mut,
         applicability = "machine-applicable",
+        style = "verbose",
         code = "let mut"
     )]
     MissingLet(#[primary_span] Span),
-    #[suggestion(parse_use_let_not_auto, applicability = "machine-applicable", code = "let")]
+    #[suggestion(
+        parse_use_let_not_auto,
+        style = "verbose",
+        applicability = "machine-applicable",
+        code = "let"
+    )]
     UseLetNotAuto(#[primary_span] Span),
-    #[suggestion(parse_use_let_not_var, applicability = "machine-applicable", code = "let")]
+    #[suggestion(
+        parse_use_let_not_var,
+        style = "verbose",
+        applicability = "machine-applicable",
+        code = "let"
+    )]
     UseLetNotVar(#[primary_span] Span),
 }
 
@@ -144,7 +179,7 @@ pub(crate) enum InvalidVariableDeclarationSub {
 #[diag(parse_switch_ref_box_order)]
 pub(crate) struct SwitchRefBoxOrder {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "box ref")]
+    #[suggestion(applicability = "machine-applicable", style = "verbose", code = "box ref")]
     pub span: Span,
 }
 
@@ -162,7 +197,7 @@ pub(crate) struct InvalidComparisonOperator {
 pub(crate) enum InvalidComparisonOperatorSub {
     #[suggestion(
         parse_use_instead,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "{correct}"
     )]
@@ -191,14 +226,14 @@ pub(crate) struct InvalidLogicalOperator {
 pub(crate) enum InvalidLogicalOperatorSub {
     #[suggestion(
         parse_use_amp_amp_for_conjunction,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "&&"
     )]
     Conjunction(#[primary_span] Span),
     #[suggestion(
         parse_use_pipe_pipe_for_disjunction,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "||"
     )]
@@ -209,7 +244,7 @@ pub(crate) enum InvalidLogicalOperatorSub {
 #[diag(parse_tilde_is_not_unary_operator)]
 pub(crate) struct TildeAsUnaryOperator(
     #[primary_span]
-    #[suggestion(style = "short", applicability = "machine-applicable", code = "!")]
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = "!")]
     pub Span,
 );
 
@@ -227,7 +262,7 @@ pub(crate) struct NotAsNegationOperator {
 pub enum NotAsNegationOperatorSub {
     #[suggestion(
         parse_unexpected_token_after_not_default,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "!"
     )]
@@ -235,7 +270,7 @@ pub enum NotAsNegationOperatorSub {
 
     #[suggestion(
         parse_unexpected_token_after_not_bitwise,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "!"
     )]
@@ -243,7 +278,7 @@ pub enum NotAsNegationOperatorSub {
 
     #[suggestion(
         parse_unexpected_token_after_not_logical,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "!"
     )]
@@ -254,9 +289,9 @@ pub enum NotAsNegationOperatorSub {
 #[diag(parse_malformed_loop_label)]
 pub(crate) struct MalformedLoopLabel {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
     pub span: Span,
-    pub correct_label: Ident,
+    #[suggestion(applicability = "machine-applicable", code = "'", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -264,7 +299,7 @@ pub(crate) struct MalformedLoopLabel {
 pub(crate) struct LifetimeInBorrowExpression {
     #[primary_span]
     pub span: Span,
-    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     #[label]
     pub lifetime_span: Span,
 }
@@ -306,7 +341,7 @@ pub(crate) struct RequireColonAfterLabeledExpression {
     pub span: Span,
     #[label]
     pub label: Span,
-    #[suggestion(style = "short", applicability = "machine-applicable", code = ": ")]
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = ": ")]
     pub label_end: Span,
 }
 
@@ -315,7 +350,7 @@ pub(crate) struct RequireColonAfterLabeledExpression {
 #[note]
 pub(crate) struct DoCatchSyntaxRemoved {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "try")]
+    #[suggestion(applicability = "machine-applicable", code = "try", style = "verbose")]
     pub span: Span,
 }
 
@@ -323,9 +358,9 @@ pub(crate) struct DoCatchSyntaxRemoved {
 #[diag(parse_float_literal_requires_integer_part)]
 pub(crate) struct FloatLiteralRequiresIntegerPart {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "{correct}")]
     pub span: Span,
-    pub correct: String,
+    #[suggestion(applicability = "machine-applicable", code = "0", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -394,7 +429,12 @@ pub struct TernaryOperator {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_extra_if_in_let_else, applicability = "maybe-incorrect", code = "")]
+#[suggestion(
+    parse_extra_if_in_let_else,
+    applicability = "maybe-incorrect",
+    code = "",
+    style = "verbose"
+)]
 pub(crate) struct IfExpressionLetSomeSub {
     #[primary_span]
     pub if_span: Span,
@@ -463,7 +503,7 @@ pub(crate) struct ExpectedElseBlock {
     pub first_tok: String,
     #[label]
     pub else_span: Span,
-    #[suggestion(applicability = "maybe-incorrect", code = "if ")]
+    #[suggestion(applicability = "maybe-incorrect", code = "if ", style = "verbose")]
     pub condition_start: Span,
 }
 
@@ -491,7 +531,7 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse {
     pub ctx_span: Span,
     pub ctx: String,
 
-    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     pub attributes: Span,
 }
 
@@ -509,12 +549,17 @@ pub(crate) enum MissingInInForLoopSub {
     // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
     #[suggestion(
         parse_use_in_not_of,
-        style = "short",
+        style = "verbose",
         applicability = "maybe-incorrect",
         code = "in"
     )]
     InNotOf(#[primary_span] Span),
-    #[suggestion(parse_add_in, style = "short", applicability = "maybe-incorrect", code = " in ")]
+    #[suggestion(
+        parse_add_in,
+        style = "verbose",
+        applicability = "maybe-incorrect",
+        code = " in "
+    )]
     AddIn(#[primary_span] Span),
 }
 
@@ -545,7 +590,7 @@ pub(crate) struct LoopElseNotSupported {
 #[diag(parse_missing_comma_after_match_arm)]
 pub(crate) struct MissingCommaAfterMatchArm {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = ",")]
+    #[suggestion(applicability = "machine-applicable", code = ",", style = "verbose")]
     pub span: Span,
 }
 
@@ -563,7 +608,7 @@ pub(crate) struct CatchAfterTry {
 pub(crate) struct CommaAfterBaseStruct {
     #[primary_span]
     pub span: Span,
-    #[suggestion(style = "short", applicability = "machine-applicable", code = "")]
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")]
     pub comma: Span,
 }
 
@@ -572,7 +617,7 @@ pub(crate) struct CommaAfterBaseStruct {
 pub(crate) struct EqFieldInit {
     #[primary_span]
     pub span: Span,
-    #[suggestion(applicability = "machine-applicable", code = ":")]
+    #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")]
     pub eq: Span,
 }
 
@@ -580,8 +625,18 @@ pub(crate) struct EqFieldInit {
 #[diag(parse_dotdotdot)]
 pub(crate) struct DotDotDot {
     #[primary_span]
-    #[suggestion(parse_suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
-    #[suggestion(parse_suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+    #[suggestion(
+        parse_suggest_exclusive_range,
+        applicability = "maybe-incorrect",
+        code = "..",
+        style = "verbose"
+    )]
+    #[suggestion(
+        parse_suggest_inclusive_range,
+        applicability = "maybe-incorrect",
+        code = "..=",
+        style = "verbose"
+    )]
     pub span: Span,
 }
 
@@ -589,7 +644,7 @@ pub(crate) struct DotDotDot {
 #[diag(parse_left_arrow_operator)]
 pub(crate) struct LeftArrowOperator {
     #[primary_span]
-    #[suggestion(applicability = "maybe-incorrect", code = "< -")]
+    #[suggestion(applicability = "maybe-incorrect", code = "< -", style = "verbose")]
     pub span: Span,
 }
 
@@ -597,7 +652,7 @@ pub(crate) struct LeftArrowOperator {
 #[diag(parse_remove_let)]
 pub(crate) struct RemoveLet {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     pub span: Span,
 }
 
@@ -605,8 +660,9 @@ pub(crate) struct RemoveLet {
 #[diag(parse_use_eq_instead)]
 pub(crate) struct UseEqInstead {
     #[primary_span]
-    #[suggestion(style = "short", applicability = "machine-applicable", code = "=")]
     pub span: Span,
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -780,7 +836,7 @@ pub(crate) struct InclusiveRangeExtraEquals {
     #[primary_span]
     #[suggestion(
         parse_suggestion_remove_eq,
-        style = "short",
+        style = "verbose",
         code = "..=",
         applicability = "maybe-incorrect"
     )]
@@ -803,13 +859,14 @@ pub(crate) struct InclusiveRangeMatchArrow {
 #[note]
 pub(crate) struct InclusiveRangeNoEnd {
     #[primary_span]
+    pub span: Span,
     #[suggestion(
         parse_suggestion_open_range,
-        code = "..",
+        code = "",
         applicability = "machine-applicable",
-        style = "short"
+        style = "verbose"
     )]
-    pub span: Span,
+    pub suggestion: Span,
 }
 
 #[derive(Subdiagnostic)]
@@ -824,7 +881,8 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg {
     #[suggestion(
         parse_suggestion_use_comma_not_semicolon,
         code = ",",
-        applicability = "machine-applicable"
+        applicability = "machine-applicable",
+        style = "verbose"
     )]
     UseComma {
         #[primary_span]
@@ -867,7 +925,7 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
 #[diag(parse_non_string_abi_literal)]
 pub(crate) struct NonStringAbiLiteral {
     #[primary_span]
-    #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")]
+    #[suggestion(code = "\"C\"", applicability = "maybe-incorrect", style = "verbose")]
     pub span: Span,
 }
 
@@ -890,7 +948,7 @@ pub(crate) struct MismatchedClosingDelimiter {
 #[help]
 pub(crate) struct IncorrectVisibilityRestriction {
     #[primary_span]
-    #[suggestion(code = "in {inner_str}", applicability = "machine-applicable")]
+    #[suggestion(code = "in {inner_str}", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub inner_str: String,
 }
@@ -915,7 +973,7 @@ pub(crate) struct ExpectedStatementAfterOuterAttr {
 pub(crate) struct DocCommentDoesNotDocumentAnything {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = ",", applicability = "machine-applicable")]
+    #[suggestion(code = ",", applicability = "machine-applicable", style = "verbose")]
     pub missing_comma: Option<Span>,
 }
 
@@ -923,7 +981,7 @@ pub(crate) struct DocCommentDoesNotDocumentAnything {
 #[diag(parse_const_let_mutually_exclusive)]
 pub(crate) struct ConstLetMutuallyExclusive {
     #[primary_span]
-    #[suggestion(code = "const", applicability = "maybe-incorrect")]
+    #[suggestion(code = "const", applicability = "maybe-incorrect", style = "verbose")]
     pub span: Span,
 }
 
@@ -951,8 +1009,9 @@ pub(crate) struct InvalidCurlyInLetElse {
 #[help]
 pub(crate) struct CompoundAssignmentExpressionInLet {
     #[primary_span]
-    #[suggestion(style = "short", code = "=", applicability = "maybe-incorrect")]
     pub span: Span,
+    #[suggestion(style = "verbose", code = "", applicability = "maybe-incorrect")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -996,7 +1055,12 @@ pub(crate) struct SuggEscapeIdentifier {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_sugg_remove_comma, applicability = "machine-applicable", code = "")]
+#[suggestion(
+    parse_sugg_remove_comma,
+    applicability = "machine-applicable",
+    code = "",
+    style = "verbose"
+)]
 pub(crate) struct SuggRemoveComma {
     #[primary_span]
     pub span: Span,
@@ -1147,13 +1211,18 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum ExpectedSemiSugg {
-    #[suggestion(parse_sugg_change_this_to_semi, code = ";", applicability = "machine-applicable")]
+    #[suggestion(
+        parse_sugg_change_this_to_semi,
+        code = ";",
+        applicability = "machine-applicable",
+        style = "short"
+    )]
     ChangeToSemi(#[primary_span] Span),
     #[suggestion(
         parse_sugg_add_semi,
-        style = "short",
         code = ";",
-        applicability = "machine-applicable"
+        applicability = "machine-applicable",
+        style = "short"
     )]
     AddSemi(#[primary_span] Span),
 }
@@ -1198,7 +1267,7 @@ pub(crate) struct StructLiteralNeedingParensSugg {
 #[diag(parse_unmatched_angle_brackets)]
 pub(crate) struct UnmatchedAngleBrackets {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub num_extra_brackets: usize,
 }
@@ -1337,7 +1406,7 @@ pub(crate) struct AttributeOnParamType {
 #[diag(parse_pattern_method_param_without_body, code = E0642)]
 pub(crate) struct PatternMethodParamWithoutBody {
     #[primary_span]
-    #[suggestion(code = "_", applicability = "machine-applicable")]
+    #[suggestion(code = "_", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -1421,7 +1490,7 @@ pub(crate) struct AsyncMoveOrderIncorrect {
 pub(crate) struct DoubleColonInBound {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = ": ", applicability = "machine-applicable")]
+    #[suggestion(code = ": ", applicability = "machine-applicable", style = "verbose")]
     pub between: Span,
 }
 
@@ -1500,9 +1569,11 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword {
 #[diag(parse_path_single_colon)]
 pub(crate) struct PathSingleColon {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "::")]
     pub span: Span,
 
+    #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")]
+    pub suggestion: Span,
+
     #[note(parse_type_ascription_removed)]
     pub type_ascription: Option<()>,
 }
@@ -1511,7 +1582,7 @@ pub(crate) struct PathSingleColon {
 #[diag(parse_colon_as_semi)]
 pub(crate) struct ColonAsSemi {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = ";")]
+    #[suggestion(applicability = "machine-applicable", code = ";", style = "verbose")]
     pub span: Span,
 
     #[note(parse_type_ascription_removed)]
@@ -1662,9 +1733,9 @@ pub(crate) enum MissingKeywordForItemDefinition {
 pub(crate) enum AmbiguousMissingKwForItemSub {
     #[suggestion(
         parse_suggestion,
-        style = "verbose",
         applicability = "maybe-incorrect",
-        code = "{snippet}!"
+        code = "{snippet}!",
+        style = "verbose"
     )]
     SuggestMacro {
         #[primary_span]
@@ -1679,7 +1750,7 @@ pub(crate) enum AmbiguousMissingKwForItemSub {
 #[diag(parse_missing_fn_params)]
 pub(crate) struct MissingFnParams {
     #[primary_span]
-    #[suggestion(code = "()", applicability = "machine-applicable", style = "short")]
+    #[suggestion(code = "()", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -1687,9 +1758,19 @@ pub(crate) struct MissingFnParams {
 #[diag(parse_missing_trait_in_trait_impl)]
 pub(crate) struct MissingTraitInTraitImpl {
     #[primary_span]
-    #[suggestion(parse_suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")]
+    #[suggestion(
+        parse_suggestion_add_trait,
+        code = " Trait ",
+        applicability = "has-placeholders",
+        style = "verbose"
+    )]
     pub span: Span,
-    #[suggestion(parse_suggestion_remove_for, code = "", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_suggestion_remove_for,
+        code = "",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     pub for_span: Span,
 }
 
@@ -1697,7 +1778,7 @@ pub(crate) struct MissingTraitInTraitImpl {
 #[diag(parse_missing_for_in_trait_impl)]
 pub(crate) struct MissingForInTraitImpl {
     #[primary_span]
-    #[suggestion(style = "short", code = " for ", applicability = "machine-applicable")]
+    #[suggestion(style = "verbose", code = " for ", applicability = "machine-applicable")]
     pub span: Span,
 }
 
@@ -1712,7 +1793,7 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType {
 #[diag(parse_extra_impl_keyword_in_trait_impl)]
 pub(crate) struct ExtraImplKeywordInTraitImpl {
     #[primary_span]
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "short")]
     pub extra_impl_kw: Span,
     #[note]
     pub impl_trait_span: Span,
@@ -1771,7 +1852,7 @@ pub(crate) struct ExternCrateNameWithDashesSugg {
 pub(crate) struct ExternItemCannotBeConst {
     #[primary_span]
     pub ident_span: Span,
-    #[suggestion(code = "static ", applicability = "machine-applicable")]
+    #[suggestion(code = "static ", applicability = "machine-applicable", style = "verbose")]
     pub const_span: Option<Span>,
 }
 
@@ -1781,7 +1862,7 @@ pub(crate) struct ConstGlobalCannotBeMutable {
     #[primary_span]
     #[label]
     pub ident_span: Span,
-    #[suggestion(code = "static", applicability = "maybe-incorrect")]
+    #[suggestion(code = "static", style = "verbose", applicability = "maybe-incorrect")]
     pub const_span: Span,
 }
 
@@ -1789,7 +1870,7 @@ pub(crate) struct ConstGlobalCannotBeMutable {
 #[diag(parse_missing_const_type)]
 pub(crate) struct MissingConstType {
     #[primary_span]
-    #[suggestion(code = "{colon} <type>", applicability = "has-placeholders")]
+    #[suggestion(code = "{colon} <type>", style = "verbose", applicability = "has-placeholders")]
     pub span: Span,
 
     pub kind: &'static str,
@@ -1800,7 +1881,7 @@ pub(crate) struct MissingConstType {
 #[diag(parse_enum_struct_mutually_exclusive)]
 pub(crate) struct EnumStructMutuallyExclusive {
     #[primary_span]
-    #[suggestion(code = "enum", applicability = "machine-applicable")]
+    #[suggestion(code = "enum", style = "verbose", applicability = "machine-applicable")]
     pub span: Span,
 }
 
@@ -2037,7 +2118,12 @@ pub struct UnknownTokenStart {
 
 #[derive(Subdiagnostic)]
 pub enum TokenSubstitution {
-    #[suggestion(parse_sugg_quotes, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_sugg_quotes,
+        code = "{suggestion}",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     DirectedQuotes {
         #[primary_span]
         span: Span,
@@ -2045,7 +2131,12 @@ pub enum TokenSubstitution {
         ascii_str: &'static str,
         ascii_name: &'static str,
     },
-    #[suggestion(parse_sugg_other, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_sugg_other,
+        code = "{suggestion}",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     Other {
         #[primary_span]
         span: Span,
@@ -2081,7 +2172,12 @@ pub enum UnescapeError {
     EscapeOnlyChar {
         #[primary_span]
         span: Span,
-        #[suggestion(parse_escape, applicability = "machine-applicable", code = "{escaped_sugg}")]
+        #[suggestion(
+            parse_escape,
+            applicability = "machine-applicable",
+            code = "{escaped_sugg}",
+            style = "verbose"
+        )]
         char_span: Span,
         escaped_sugg: String,
         escaped_msg: String,
@@ -2090,7 +2186,12 @@ pub enum UnescapeError {
     #[diag(parse_bare_cr)]
     BareCr {
         #[primary_span]
-        #[suggestion(parse_escape, applicability = "machine-applicable", code = "\\r")]
+        #[suggestion(
+            parse_escape,
+            applicability = "machine-applicable",
+            code = "\\r",
+            style = "verbose"
+        )]
         span: Span,
         double_quotes: bool,
     },
@@ -2207,7 +2308,8 @@ pub enum MoreThanOneCharSugg {
     #[suggestion(
         parse_consider_normalized,
         code = "{normalized}",
-        applicability = "machine-applicable"
+        applicability = "machine-applicable",
+        style = "verbose"
     )]
     NormalizedForm {
         #[primary_span]
@@ -2215,13 +2317,23 @@ pub enum MoreThanOneCharSugg {
         ch: String,
         normalized: String,
     },
-    #[suggestion(parse_remove_non, code = "{ch}", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_remove_non,
+        code = "{ch}",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     RemoveNonPrinting {
         #[primary_span]
         span: Span,
         ch: String,
     },
-    #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")]
+    #[suggestion(
+        parse_use_double_quotes,
+        code = "{sugg}",
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
     QuotesFull {
         #[primary_span]
         span: Span,
@@ -2259,7 +2371,12 @@ pub enum MoreThanOneCharNote {
 
 #[derive(Subdiagnostic)]
 pub enum NoBraceUnicodeSub {
-    #[suggestion(parse_use_braces, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_use_braces,
+        code = "{suggestion}",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     Suggestion {
         #[primary_span]
         span: Span,
@@ -2270,26 +2387,31 @@ pub enum NoBraceUnicodeSub {
 }
 
 #[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_sugg_wrap_pattern_in_parens, applicability = "machine-applicable")]
+pub(crate) struct WrapInParens {
+    #[suggestion_part(code = "(")]
+    pub(crate) lo: Span,
+    #[suggestion_part(code = ")")]
+    pub(crate) hi: Span,
+}
+
+#[derive(Subdiagnostic)]
 pub(crate) enum TopLevelOrPatternNotAllowedSugg {
     #[suggestion(
         parse_sugg_remove_leading_vert_in_pattern,
-        code = "{pat}",
-        applicability = "machine-applicable"
+        code = "",
+        applicability = "machine-applicable",
+        style = "verbose"
     )]
     RemoveLeadingVert {
         #[primary_span]
         span: Span,
-        pat: String,
     },
-    #[suggestion(
-        parse_sugg_wrap_pattern_in_parens,
-        code = "({pat})",
-        applicability = "machine-applicable"
-    )]
     WrapInParens {
         #[primary_span]
         span: Span,
-        pat: String,
+        #[subdiagnostic]
+        suggestion: WrapInParens,
     },
 }
 
@@ -2298,7 +2420,7 @@ pub(crate) enum TopLevelOrPatternNotAllowedSugg {
 #[note(parse_note_pattern_alternatives_use_single_vert)]
 pub(crate) struct UnexpectedVertVertBeforeFunctionParam {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2306,7 +2428,7 @@ pub(crate) struct UnexpectedVertVertBeforeFunctionParam {
 #[diag(parse_unexpected_vert_vert_in_pattern)]
 pub(crate) struct UnexpectedVertVertInPattern {
     #[primary_span]
-    #[suggestion(code = "|", applicability = "machine-applicable")]
+    #[suggestion(code = "|", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     #[label(parse_label_while_parsing_or_pattern_here)]
     pub start: Option<Span>,
@@ -2316,7 +2438,7 @@ pub(crate) struct UnexpectedVertVertInPattern {
 #[diag(parse_trailing_vert_not_allowed)]
 pub(crate) struct TrailingVertNotAllowed {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     #[label(parse_label_while_parsing_or_pattern_here)]
     pub start: Option<Span>,
@@ -2329,16 +2451,17 @@ pub(crate) struct TrailingVertNotAllowed {
 #[diag(parse_dotdotdot_rest_pattern)]
 pub(crate) struct DotDotDotRestPattern {
     #[primary_span]
-    #[suggestion(style = "short", code = "..", applicability = "machine-applicable")]
     #[label]
     pub span: Span,
+    #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
 #[diag(parse_pattern_on_wrong_side_of_at)]
 pub(crate) struct PatternOnWrongSideOfAt {
     #[primary_span]
-    #[suggestion(code = "{whole_pat}", applicability = "machine-applicable")]
+    #[suggestion(code = "{whole_pat}", applicability = "machine-applicable", style = "verbose")]
     pub whole_span: Span,
     pub whole_pat: String,
     #[label(parse_label_pattern)]
@@ -2359,22 +2482,35 @@ pub(crate) struct ExpectedBindingLeftOfAt {
     pub rhs: Span,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    parse_ambiguous_range_pattern_suggestion,
+    applicability = "machine-applicable"
+)]
+pub(crate) struct ParenRangeSuggestion {
+    #[suggestion_part(code = "(")]
+    pub lo: Span,
+    #[suggestion_part(code = ")")]
+    pub hi: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_ambiguous_range_pattern)]
 pub(crate) struct AmbiguousRangePattern {
     #[primary_span]
-    #[suggestion(code = "({pat})", applicability = "maybe-incorrect")]
     pub span: Span,
-    pub pat: String,
+    #[subdiagnostic]
+    pub suggestion: ParenRangeSuggestion,
 }
 
 #[derive(Diagnostic)]
 #[diag(parse_unexpected_lifetime_in_pattern)]
 pub(crate) struct UnexpectedLifetimeInPattern {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
     pub span: Span,
     pub symbol: Symbol,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -2383,7 +2519,7 @@ pub(crate) enum InvalidMutInPattern {
     #[note(parse_note_mut_pattern_usage)]
     NestedIdent {
         #[primary_span]
-        #[suggestion(code = "{pat}", applicability = "machine-applicable")]
+        #[suggestion(code = "{pat}", applicability = "machine-applicable", style = "verbose")]
         span: Span,
         pat: String,
     },
@@ -2391,7 +2527,7 @@ pub(crate) enum InvalidMutInPattern {
     #[note(parse_note_mut_pattern_usage)]
     NonIdent {
         #[primary_span]
-        #[suggestion(code = "", applicability = "machine-applicable")]
+        #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
         span: Span,
     },
 }
@@ -2400,7 +2536,7 @@ pub(crate) enum InvalidMutInPattern {
 #[diag(parse_repeated_mut_in_pattern)]
 pub(crate) struct RepeatedMutInPattern {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2408,7 +2544,7 @@ pub(crate) struct RepeatedMutInPattern {
 #[diag(parse_dot_dot_dot_range_to_pattern_not_allowed)]
 pub(crate) struct DotDotDotRangeToPatternNotAllowed {
     #[primary_span]
-    #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")]
+    #[suggestion(style = "verbose", code = "..=", applicability = "machine-applicable")]
     pub span: Span,
 }
 
@@ -2472,8 +2608,9 @@ pub(crate) struct UnexpectedParenInRangePatSugg {
 #[diag(parse_return_types_use_thin_arrow)]
 pub(crate) struct ReturnTypesUseThinArrow {
     #[primary_span]
-    #[suggestion(style = "short", code = "->", applicability = "machine-applicable")]
     pub span: Span,
+    #[suggestion(style = "verbose", code = " -> ", applicability = "machine-applicable")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -2488,7 +2625,7 @@ pub(crate) struct NeedPlusAfterTraitObjectLifetime {
 pub(crate) struct ExpectedMutOrConstInRawPointerType {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code("mut ", "const "), applicability = "has-placeholders")]
+    #[suggestion(code("mut ", "const "), applicability = "has-placeholders", style = "verbose")]
     pub after_asterisk: Span,
 }
 
@@ -2497,7 +2634,7 @@ pub(crate) struct ExpectedMutOrConstInRawPointerType {
 pub(crate) struct LifetimeAfterMut {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect")]
+    #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect", style = "verbose")]
     pub suggest_lifetime: Option<Span>,
     pub snippet: String,
 }
@@ -2506,7 +2643,7 @@ pub(crate) struct LifetimeAfterMut {
 #[diag(parse_dyn_after_mut)]
 pub(crate) struct DynAfterMut {
     #[primary_span]
-    #[suggestion(code = "&mut dyn", applicability = "machine-applicable")]
+    #[suggestion(code = "&mut dyn", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2515,7 +2652,7 @@ pub(crate) struct DynAfterMut {
 pub(crate) struct FnPointerCannotBeConst {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     #[label]
     pub qualifier: Span,
 }
@@ -2525,7 +2662,7 @@ pub(crate) struct FnPointerCannotBeConst {
 pub(crate) struct FnPointerCannotBeAsync {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     #[label]
     pub qualifier: Span,
 }
@@ -2542,8 +2679,9 @@ pub(crate) struct NestedCVariadicType {
 #[help]
 pub(crate) struct InvalidDynKeyword {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
     pub span: Span,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Subdiagnostic)]
@@ -2584,7 +2722,7 @@ pub struct BoxSyntaxRemoved<'a> {
 #[diag(parse_bad_return_type_notation_output)]
 pub(crate) struct BadReturnTypeNotationOutput {
     #[primary_span]
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub span: Span,
 }
 
@@ -2655,14 +2793,25 @@ pub(crate) struct ModifierLifetime {
     pub modifier: &'static str,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    parse_parenthesized_lifetime_suggestion,
+    applicability = "machine-applicable"
+)]
+pub(crate) struct RemoveParens {
+    #[suggestion_part(code = "")]
+    pub lo: Span,
+    #[suggestion_part(code = "")]
+    pub hi: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_parenthesized_lifetime)]
 pub(crate) struct ParenthesizedLifetime {
     #[primary_span]
     pub span: Span,
-    #[suggestion(style = "short", applicability = "machine-applicable", code = "{snippet}")]
-    pub sugg: Option<Span>,
-    pub snippet: String,
+    #[subdiagnostic]
+    pub sugg: RemoveParens,
 }
 
 #[derive(Diagnostic)]
@@ -2677,7 +2826,7 @@ pub(crate) struct UnderscoreLiteralSuffix {
 pub(crate) struct ExpectedLabelFoundIdent {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "'", applicability = "machine-applicable", style = "short")]
+    #[suggestion(code = "'", applicability = "machine-applicable", style = "verbose")]
     pub start: Span,
 }
 
@@ -2696,7 +2845,7 @@ pub(crate) struct InappropriateDefault {
 #[diag(parse_recover_import_as_use)]
 pub(crate) struct RecoverImportAsUse {
     #[primary_span]
-    #[suggestion(code = "use", applicability = "machine-applicable", style = "short")]
+    #[suggestion(code = "use", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub token_name: String,
 }
@@ -2706,7 +2855,7 @@ pub(crate) struct RecoverImportAsUse {
 #[note]
 pub(crate) struct SingleColonImportPath {
     #[primary_span]
-    #[suggestion(code = "::", applicability = "machine-applicable", style = "short")]
+    #[suggestion(code = "::", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2733,7 +2882,7 @@ pub(crate) struct SingleColonStructType {
 #[diag(parse_equals_struct_default)]
 pub(crate) struct EqualsStructDefault {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2750,7 +2899,7 @@ pub(crate) struct MacroRulesMissingBang {
 #[diag(parse_macro_name_remove_bang)]
 pub(crate) struct MacroNameRemoveBang {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "short")]
     pub span: Span,
 }
 
@@ -2758,7 +2907,7 @@ pub(crate) struct MacroNameRemoveBang {
 #[diag(parse_macro_rules_visibility)]
 pub(crate) struct MacroRulesVisibility<'a> {
     #[primary_span]
-    #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect")]
+    #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect", style = "verbose")]
     pub span: Span,
     pub vis: &'a str,
 }
@@ -2768,7 +2917,7 @@ pub(crate) struct MacroRulesVisibility<'a> {
 #[help]
 pub(crate) struct MacroInvocationVisibility<'a> {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub vis: &'a str,
 }
@@ -2778,7 +2927,7 @@ pub(crate) struct MacroInvocationVisibility<'a> {
 pub(crate) struct NestedAdt<'a> {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub item: Span,
     pub keyword: &'a str,
     pub kw_str: Cow<'a, str>,
@@ -2818,7 +2967,7 @@ pub(crate) struct BoxNotPat {
 #[diag(parse_unmatched_angle)]
 pub(crate) struct UnmatchedAngle {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub plural: bool,
 }
@@ -2858,7 +3007,7 @@ pub(crate) struct IncorrectParensTraitBoundsSugg {
 #[diag(parse_kw_bad_case)]
 pub(crate) struct KwBadCase<'a> {
     #[primary_span]
-    #[suggestion(code = "{kw}", applicability = "machine-applicable")]
+    #[suggestion(code = "{kw}", style = "verbose", applicability = "machine-applicable")]
     pub span: Span,
     pub kw: &'a str,
 }
@@ -2895,7 +3044,7 @@ pub(crate) struct MetaBadDelimSugg {
 #[note]
 pub(crate) struct MalformedCfgAttr {
     #[primary_span]
-    #[suggestion(code = "{sugg}")]
+    #[suggestion(style = "verbose", code = "{sugg}")]
     pub span: Span,
     pub sugg: &'static str,
 }
@@ -3000,7 +3149,7 @@ pub(crate) struct AsyncImpl {
 #[help]
 pub(crate) struct ExprRArrowCall {
     #[primary_span]
-    #[suggestion(style = "short", applicability = "machine-applicable", code = ".")]
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = ".")]
     pub span: Span,
 }
 
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 5522127be83..4454747ea02 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -157,14 +157,14 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
 }
 
 pub fn parse_cfg_attr(
-    attr: &Attribute,
+    cfg_attr: &Attribute,
     psess: &ParseSess,
 ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
     const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
     const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
         <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";
 
-    match attr.get_normal_item().args {
+    match cfg_attr.get_normal_item().args {
         ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
             if !tokens.is_empty() =>
         {
@@ -180,7 +180,7 @@ pub fn parse_cfg_attr(
         }
         _ => {
             psess.dcx().emit_err(errors::MalformedCfgAttr {
-                span: attr.span,
+                span: cfg_attr.span,
                 sugg: CFG_ATTR_GRAMMAR_HELP,
             });
         }
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 38f18022e3c..1123c31f551 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -103,11 +103,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
         // produce an empty `TokenStream` if no calls were made, and omit the
         // final token otherwise.
         let mut cursor_snapshot = self.cursor_snapshot.clone();
-        let tokens = iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
-            .chain(iter::repeat_with(|| {
-                let token = cursor_snapshot.next();
-                (FlatToken::Token(token.0), token.1)
-            }))
+        let tokens = iter::once(FlatToken::Token(self.start_token.clone()))
+            .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next())))
             .take(self.num_calls as usize);
 
         if self.replace_ranges.is_empty() {
@@ -156,11 +153,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
                     (range.start as usize)..(range.end as usize),
                     target
                         .into_iter()
-                        .map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone))
-                        .chain(
-                            iter::repeat((FlatToken::Empty, Spacing::Alone))
-                                .take(range.len() - target_len),
-                        ),
+                        .map(|target| FlatToken::AttrsTarget(target))
+                        .chain(iter::repeat(FlatToken::Empty).take(range.len() - target_len)),
                 );
             }
             make_attr_token_stream(tokens.into_iter(), self.break_last_token)
@@ -301,21 +295,22 @@ impl<'a> Parser<'a> {
 
         let num_calls = end_pos - start_pos;
 
-        // If we have no attributes, then we will never need to
-        // use any replace ranges.
-        let replace_ranges: Box<[ReplaceRange]> = if ret.attrs().is_empty() && !self.capture_cfg {
-            Box::new([])
-        } else {
-            // Grab any replace ranges that occur *inside* the current AST node.
-            // We will perform the actual replacement 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()
-        };
+        // 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 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 tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl {
             start_token,
@@ -325,12 +320,9 @@ impl<'a> Parser<'a> {
             replace_ranges,
         });
 
-        // If we support tokens at all
-        if let Some(target_tokens) = ret.tokens_mut() {
-            if target_tokens.is_none() {
-                // Store our newly captured tokens into the AST node.
-                *target_tokens = Some(tokens.clone());
-            }
+        // If we support tokens and don't already have them, store the newly captured tokens.
+        if let Some(target_tokens @ None) = ret.tokens_mut() {
+            *target_tokens = Some(tokens.clone());
         }
 
         let final_attrs = ret.attrs();
@@ -352,15 +344,10 @@ impl<'a> Parser<'a> {
             let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens };
             self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target)));
             self.capture_state.replace_ranges.extend(inner_attr_replace_ranges);
-        }
-
-        // Only clear our `replace_ranges` when we're finished capturing entirely.
-        if matches!(self.capture_state.capturing, Capturing::No) {
+        } else if matches!(self.capture_state.capturing, Capturing::No) {
+            // Only clear the ranges once we've finished capturing entirely.
             self.capture_state.replace_ranges.clear();
-            // We don't clear `inner_attr_ranges`, as doing so repeatedly
-            // had a measurable performance impact. Most inner attributes that
-            // we insert will get removed - when we drop the parser, we'll free
-            // up the memory used by any attributes that we didn't remove from the map.
+            self.capture_state.inner_attr_ranges.clear();
         }
         Ok(ret)
     }
@@ -370,7 +357,7 @@ impl<'a> Parser<'a> {
 /// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and
 /// close delims.
 fn make_attr_token_stream(
-    mut iter: impl Iterator<Item = (FlatToken, Spacing)>,
+    iter: impl Iterator<Item = FlatToken>,
     break_last_token: bool,
 ) -> AttrTokenStream {
     #[derive(Debug)]
@@ -379,19 +366,19 @@ fn make_attr_token_stream(
         open_delim_sp: Option<(Delimiter, Span, Spacing)>,
         inner: Vec<AttrTokenTree>,
     }
-    let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }];
-    let mut token_and_spacing = iter.next();
-    while let Some((token, spacing)) = token_and_spacing {
-        match token {
-            FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => {
-                stack
-                    .push(FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] });
+    // The stack always has at least one element. Storing it separately makes for shorter code.
+    let mut stack_top = FrameData { open_delim_sp: None, inner: vec![] };
+    let mut stack_rest = vec![];
+    for flat_token in iter {
+        match flat_token {
+            FlatToken::Token((Token { kind: TokenKind::OpenDelim(delim), span }, spacing)) => {
+                stack_rest.push(mem::replace(
+                    &mut stack_top,
+                    FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
+                ));
             }
-            FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => {
-                let frame_data = stack
-                    .pop()
-                    .unwrap_or_else(|| panic!("Token stack was empty for token: {token:?}"));
-
+            FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => {
+                let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
                 let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
                 assert_eq!(
                     open_delim, delim,
@@ -401,29 +388,20 @@ fn make_attr_token_stream(
                 let dspacing = DelimSpacing::new(open_spacing, spacing);
                 let stream = AttrTokenStream::new(frame_data.inner);
                 let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream);
-                stack
-                    .last_mut()
-                    .unwrap_or_else(|| panic!("Bottom token frame is missing for token: {token:?}"))
-                    .inner
-                    .push(delimited);
+                stack_top.inner.push(delimited);
+            }
+            FlatToken::Token((token, spacing)) => {
+                stack_top.inner.push(AttrTokenTree::Token(token, spacing))
+            }
+            FlatToken::AttrsTarget(target) => {
+                stack_top.inner.push(AttrTokenTree::AttrsTarget(target))
             }
-            FlatToken::Token(token) => stack
-                .last_mut()
-                .expect("Bottom token frame is missing!")
-                .inner
-                .push(AttrTokenTree::Token(token, spacing)),
-            FlatToken::AttrsTarget(target) => stack
-                .last_mut()
-                .expect("Bottom token frame is missing!")
-                .inner
-                .push(AttrTokenTree::AttrsTarget(target)),
             FlatToken::Empty => {}
         }
-        token_and_spacing = iter.next();
     }
-    let mut final_buf = stack.pop().expect("Missing final buf!");
+
     if break_last_token {
-        let last_token = final_buf.inner.pop().unwrap();
+        let last_token = stack_top.inner.pop().unwrap();
         if let AttrTokenTree::Token(last_token, spacing) = last_token {
             let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
 
@@ -431,14 +409,14 @@ fn make_attr_token_stream(
             let mut first_span = last_token.span.shrink_to_lo();
             first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
 
-            final_buf
+            stack_top
                 .inner
                 .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
         } else {
             panic!("Unexpected last token {last_token:?}")
         }
     }
-    AttrTokenStream::new(final_buf.inner)
+    AttrTokenStream::new(stack_top.inner)
 }
 
 // Some types are used a lot. Make sure they don't unintentionally get bigger.
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 81d5f0fca0e..0da7fefe6ed 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -3,8 +3,8 @@ use super::{
     BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType,
 };
 use crate::errors::{
-    AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus,
-    BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
+    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion,
+    BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
     ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
     ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
     DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
@@ -566,7 +566,10 @@ impl<'a> Parser<'a> {
             && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
         {
             // Likely typo: `=` → `==` in let expr or enum item
-            return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
+            return Err(self.dcx().create_err(UseEqInstead {
+                span: self.token.span,
+                suggestion: self.token.span.with_lo(self.token.span.lo() + BytePos(1)),
+            }));
         }
 
         if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) {
@@ -1151,7 +1154,7 @@ impl<'a> Parser<'a> {
             // Eat from where we started until the end token so that parsing can continue
             // as if we didn't have those extra angle brackets.
             self.eat_to_tokens(end);
-            let span = lo.until(self.token.span);
+            let span = lo.to(self.prev_token.span);
 
             let num_extra_brackets = number_of_gt + number_of_shr * 2;
             return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets }));
@@ -1539,7 +1542,10 @@ impl<'a> Parser<'a> {
 
     pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
         if impl_dyn_multi {
-            self.dcx().emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(ty), span: ty.span });
+            self.dcx().emit_err(AmbiguousPlus {
+                span: ty.span,
+                suggestion: AddParen { lo: ty.span.shrink_to_lo(), hi: ty.span.shrink_to_hi() },
+            });
         }
     }
 
@@ -1604,25 +1610,14 @@ impl<'a> Parser<'a> {
         }
 
         self.bump(); // `+`
-        let bounds = self.parse_generic_bounds()?;
+        let _bounds = self.parse_generic_bounds()?;
         let sum_span = ty.span.to(self.prev_token.span);
 
         let sub = match &ty.kind {
-            TyKind::Ref(lifetime, mut_ty) => {
-                let sum_with_parens = pprust::to_string(|s| {
-                    s.s.word("&");
-                    s.print_opt_lifetime(lifetime);
-                    s.print_mutability(mut_ty.mutbl, false);
-                    s.popen();
-                    s.print_type(&mut_ty.ty);
-                    if !bounds.is_empty() {
-                        s.word(" + ");
-                        s.print_type_bounds(&bounds);
-                    }
-                    s.pclose()
-                });
-
-                BadTypePlusSub::AddParen { sum_with_parens, span: sum_span }
+            TyKind::Ref(_lifetime, mut_ty) => {
+                let lo = mut_ty.ty.span.shrink_to_lo();
+                let hi = self.prev_token.span.shrink_to_hi();
+                BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
             }
             TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span },
             _ => BadTypePlusSub::ExpectPath { span: sum_span },
@@ -1964,18 +1959,14 @@ impl<'a> Parser<'a> {
         is_question: bool,
     ) -> (Span, ErrorGuaranteed) {
         let span = lo.to(hi);
-        let applicability = match expr.kind {
-            ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
-            _ => Applicability::MachineApplicable,
-        };
-
         let guar = self.dcx().emit_err(IncorrectAwait {
             span,
-            sugg_span: (span, applicability),
-            expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(expr)),
-            question_mark: if is_question { "?" } else { "" },
+            suggestion: AwaitSuggestion {
+                removal: lo.until(expr.span),
+                dot_await: expr.span.shrink_to_hi(),
+                question_mark: if is_question { "?" } else { "" },
+            },
         });
-
         (span, guar)
     }
 
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index b2df9a14eb0..4bd20be4171 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -714,7 +714,7 @@ impl<'a> Parser<'a> {
                                 type_err.cancel();
                                 self.dcx().emit_err(errors::MalformedLoopLabel {
                                     span: label.ident.span,
-                                    correct_label: label.ident,
+                                    suggestion: label.ident.span.shrink_to_lo(),
                                 });
                                 return Ok(expr);
                             }
@@ -856,7 +856,7 @@ impl<'a> Parser<'a> {
         let hi = self.interpolated_or_expr_span(&expr);
         let span = lo.to(hi);
         if let Some(lt) = lifetime {
-            self.error_remove_borrow_lifetime(span, lt.ident.span);
+            self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
         }
         Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
     }
@@ -1653,6 +1653,7 @@ impl<'a> Parser<'a> {
         let lo = label_.ident.span;
         let label = Some(label_);
         let ate_colon = self.eat(&token::Colon);
+        let tok_sp = self.token.span;
         let expr = if self.eat_keyword(kw::While) {
             self.parse_expr_while(label, lo)
         } else if self.eat_keyword(kw::For) {
@@ -1747,7 +1748,7 @@ impl<'a> Parser<'a> {
             self.dcx().emit_err(errors::RequireColonAfterLabeledExpression {
                 span: expr.span,
                 label: lo,
-                label_end: lo.shrink_to_hi(),
+                label_end: lo.between(tok_sp),
             });
         }
 
@@ -2106,7 +2107,7 @@ impl<'a> Parser<'a> {
                 self.bump();
                 self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart {
                     span: token.span,
-                    correct: pprust::token_to_string(token).into_owned(),
+                    suggestion: token.span.shrink_to_lo(),
                 });
             }
         }
@@ -2741,7 +2742,7 @@ impl<'a> Parser<'a> {
         if !attrs.is_empty()
             && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
         {
-            let attributes = x0.span.to(xn.span);
+            let attributes = x0.span.until(branch_span);
             let last = xn.span;
             let ctx = if is_ctx_else { "else" } else { "if" };
             self.dcx().emit_err(errors::OuterAttributeNotAllowedOnIfElse {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index f31e634f55c..76857cb8504 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -387,8 +387,8 @@ impl<'a> Parser<'a> {
         let span = if is_pub { self.prev_token.span.to(ident_span) } else { ident_span };
         let insert_span = ident_span.shrink_to_lo();
 
-        let ident = if (!is_const
-            || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)))
+        let ident = if self.token.is_ident()
+            && (!is_const || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)))
             && self.look_ahead(1, |t| {
                 [
                     token::Lt,
@@ -810,7 +810,7 @@ impl<'a> Parser<'a> {
                         self.dcx().struct_span_err(non_item_span, "non-item in item list");
                     self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
                     if is_let {
-                        err.span_suggestion(
+                        err.span_suggestion_verbose(
                             non_item_span,
                             "consider using `const` instead of `let` for associated const",
                             "const",
@@ -2241,9 +2241,13 @@ impl<'a> Parser<'a> {
             let kw_token = self.token.clone();
             let kw_str = pprust::token_to_string(&kw_token);
             let item = self.parse_item(ForceCollect::No)?;
+            let mut item = item.unwrap().span;
+            if self.token == token::Comma {
+                item = item.to(self.token.span);
+            }
             self.dcx().emit_err(errors::NestedAdt {
                 span: kw_token.span,
-                item: item.unwrap().span,
+                item,
                 kw_str,
                 keyword: keyword.as_str(),
             });
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 45ca267fe5d..958458eda9a 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1118,41 +1118,37 @@ impl<'a> Parser<'a> {
             return looker(&self.token);
         }
 
-        if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last()
-            && delim != Delimiter::Invisible
-        {
-            // We are not in the outermost token stream, and the token stream
-            // we are in has non-skipped delimiters. Look for skipped
-            // delimiters in the lookahead range.
-            let tree_cursor = &self.token_cursor.tree_cursor;
-            let all_normal = (0..dist).all(|i| {
-                let token = tree_cursor.look_ahead(i);
-                !matches!(token, Some(TokenTree::Delimited(.., Delimiter::Invisible, _)))
-            });
-            if all_normal {
-                // There were no skipped delimiters. Do lookahead by plain indexing.
-                return match tree_cursor.look_ahead(dist - 1) {
-                    Some(tree) => {
-                        // Indexing stayed within the current token stream.
-                        match tree {
-                            TokenTree::Token(token, _) => looker(token),
-                            TokenTree::Delimited(dspan, _, delim, _) => {
-                                looker(&Token::new(token::OpenDelim(*delim), dspan.open))
-                            }
+        // Typically around 98% of the `dist > 0` cases have `dist == 1`, so we
+        // have a fast special case for that.
+        if dist == 1 {
+            // The index is zero because the tree cursor's index always points
+            // to the next token to be gotten.
+            match self.token_cursor.tree_cursor.look_ahead(0) {
+                Some(tree) => {
+                    // Indexing stayed within the current token tree.
+                    return match tree {
+                        TokenTree::Token(token, _) => looker(token),
+                        TokenTree::Delimited(dspan, _, delim, _) => {
+                            looker(&Token::new(token::OpenDelim(*delim), dspan.open))
                         }
+                    };
+                }
+                None => {
+                    // The tree cursor lookahead went (one) past the end of the
+                    // current token tree. Try to return a close delimiter.
+                    if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last()
+                        && delim != Delimiter::Invisible
+                    {
+                        // We are not in the outermost token stream, so we have
+                        // delimiters. Also, those delimiters are not skipped.
+                        return looker(&Token::new(token::CloseDelim(delim), span.close));
                     }
-                    None => {
-                        // Indexing went past the end of the current token
-                        // stream. Use the close delimiter, no matter how far
-                        // ahead `dist` went.
-                        looker(&Token::new(token::CloseDelim(delim), span.close))
-                    }
-                };
+                }
             }
         }
 
-        // We are in a more complex case. Just clone the token cursor and use
-        // `next`, skipping delimiters as necessary. Slow but simple.
+        // Just clone the token cursor and use `next`, skipping delimiters as
+        // necessary. Slow but simple.
         let mut cursor = self.token_cursor.clone();
         let mut i = 0;
         let mut token = Token::dummy();
@@ -1541,14 +1537,16 @@ impl<'a> Parser<'a> {
 
                 // we don't need N spans, but we want at least one, so print all of prev_token
                 dbg_fmt.field("prev_token", &parser.prev_token);
-                // make it easier to peek farther ahead by taking TokenKinds only until EOF
-                let tokens = (0..*lookahead)
-                    .map(|i| parser.look_ahead(i, |tok| tok.kind.clone()))
-                    .scan(parser.prev_token == TokenKind::Eof, |eof, tok| {
-                        let current = eof.then_some(tok.clone()); // include a trailing EOF token
-                        *eof |= &tok == &TokenKind::Eof;
-                        current
-                    });
+                let mut tokens = vec![];
+                for i in 0..*lookahead {
+                    let tok = parser.look_ahead(i, |tok| tok.kind.clone());
+                    let is_eof = tok == TokenKind::Eof;
+                    tokens.push(tok);
+                    if is_eof {
+                        // Don't look ahead past EOF.
+                        break;
+                    }
+                }
                 dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish());
                 dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls);
 
@@ -1607,7 +1605,7 @@ pub(crate) fn make_unclosed_delims_error(
 enum FlatToken {
     /// A token - this holds both delimiter (e.g. '{' and '}')
     /// and non-delimiter tokens
-    Token(Token),
+    Token((Token, Spacing)),
     /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted
     /// directly into the constructed `AttrTokenStream` as an
     /// `AttrTokenTree::AttrsTarget`.
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 6f2b7177159..e4e89615d71 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -4,11 +4,11 @@ use crate::errors::{
     DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
     ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
     InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
-    PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder,
-    TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed,
-    UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
-    UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
-    UnexpectedVertVertInPattern,
+    ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern,
+    SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
+    TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
+    UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
+    UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
 };
 use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -24,7 +24,7 @@ use rustc_errors::{Applicability, Diag, PResult};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{ErrorGuaranteed, Span};
+use rustc_span::{BytePos, ErrorGuaranteed, Span};
 use thin_vec::{thin_vec, ThinVec};
 
 #[derive(PartialEq, Copy, Clone)]
@@ -236,11 +236,15 @@ impl<'a> Parser<'a> {
 
         if let PatKind::Or(pats) = &pat.kind {
             let span = pat.span;
-            let pat = pprust::pat_to_string(&pat);
             let sub = if pats.len() == 1 {
-                Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat })
+                Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert {
+                    span: span.with_hi(span.lo() + BytePos(1)),
+                })
             } else {
-                Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat })
+                Some(TopLevelOrPatternNotAllowedSugg::WrapInParens {
+                    span,
+                    suggestion: WrapInParens { lo: span.shrink_to_lo(), hi: span.shrink_to_hi() },
+                })
             };
 
             let err = self.dcx().create_err(match syntax_loc {
@@ -599,7 +603,10 @@ impl<'a> Parser<'a> {
         self.bump(); // `...`
 
         // The user probably mistook `...` for a rest pattern `..`.
-        self.dcx().emit_err(DotDotDotRestPattern { span: lo });
+        self.dcx().emit_err(DotDotDotRestPattern {
+            span: lo,
+            suggestion: lo.with_lo(lo.hi() - BytePos(1)),
+        });
         PatKind::Rest
     }
 
@@ -664,8 +671,13 @@ impl<'a> Parser<'a> {
             _ => return,
         }
 
-        self.dcx()
-            .emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(pat) });
+        self.dcx().emit_err(AmbiguousRangePattern {
+            span: pat.span,
+            suggestion: ParenRangeSuggestion {
+                lo: pat.span.shrink_to_lo(),
+                hi: pat.span.shrink_to_hi(),
+            },
+        });
     }
 
     /// Parse `&pat` / `&mut pat`.
@@ -674,8 +686,11 @@ impl<'a> Parser<'a> {
         if let token::Lifetime(name) = self.token.kind {
             self.bump(); // `'a`
 
-            self.dcx()
-                .emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name });
+            self.dcx().emit_err(UnexpectedLifetimeInPattern {
+                span: self.prev_token.span,
+                symbol: name,
+                suggestion: self.prev_token.span.until(self.token.span),
+            });
         }
 
         let mutbl = self.parse_mutability();
@@ -913,10 +928,13 @@ impl<'a> Parser<'a> {
                 self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq })
             }
             token::Gt if no_space => {
-                let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
+                let after_pat = span.with_hi(span.hi() - BytePos(1)).shrink_to_hi();
                 self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat })
             }
-            _ => self.dcx().emit_err(InclusiveRangeNoEnd { span }),
+            _ => self.dcx().emit_err(InclusiveRangeNoEnd {
+                span,
+                suggestion: span.with_lo(span.hi() - BytePos(1)),
+            }),
         }
     }
 
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 03c647dd527..b9014dea726 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -258,6 +258,7 @@ impl<'a> Parser<'a> {
                         self.bump(); // bump past the colon
                         self.dcx().emit_err(PathSingleColon {
                             span: self.prev_token.span,
+                            suggestion: self.prev_token.span.shrink_to_hi(),
                             type_ascription: self
                                 .psess
                                 .unstable_features
@@ -329,6 +330,7 @@ impl<'a> Parser<'a> {
                             err.cancel();
                             err = self.dcx().create_err(PathSingleColon {
                                 span: self.token.span,
+                                suggestion: self.prev_token.span.shrink_to_hi(),
                                 type_ascription: self
                                     .psess
                                     .unstable_features
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index d65f6ff68ee..70d41de00a7 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -430,8 +430,10 @@ impl<'a> Parser<'a> {
         let eq_consumed = match self.token.kind {
             token::BinOpEq(..) => {
                 // Recover `let x <op>= 1` as `let x = 1`
-                self.dcx()
-                    .emit_err(errors::CompoundAssignmentExpressionInLet { span: 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)),
+                });
                 self.bump();
                 true
             }
@@ -717,7 +719,7 @@ impl<'a> Parser<'a> {
                                                 e.cancel();
                                                 self.dcx().emit_err(MalformedLoopLabel {
                                                     span: label.ident.span,
-                                                    correct_label: label.ident,
+                                                    suggestion: label.ident.span.shrink_to_lo(),
                                                 });
                                                 *expr = labeled_expr;
                                                 break 'break_recover None;
diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs
index 42392ad2163..cf791d332a2 100644
--- a/compiler/rustc_parse/src/parser/tests.rs
+++ b/compiler/rustc_parse/src/parser/tests.rs
@@ -1376,6 +1376,365 @@ fn ttdelim_span() {
     });
 }
 
+#[track_caller]
+fn look(p: &Parser<'_>, dist: usize, kind: rustc_ast::token::TokenKind) {
+    // Do the `assert_eq` outside the closure so that `track_caller` works.
+    // (`#![feature(closure_track_caller)]` + `#[track_caller]` on the closure
+    // doesn't give the line number in the test below if the assertion fails.)
+    let tok = p.look_ahead(dist, |tok| tok.clone());
+    assert_eq!(kind, tok.kind);
+}
+
+#[test]
+fn look_ahead() {
+    create_default_session_globals_then(|| {
+        let sym_f = Symbol::intern("f");
+        let sym_x = Symbol::intern("x");
+        #[allow(non_snake_case)]
+        let sym_S = Symbol::intern("S");
+        let raw_no = IdentIsRaw::No;
+
+        let psess = psess();
+        let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string());
+
+        // Current position is the `fn`.
+        look(&p, 0, token::Ident(kw::Fn, raw_no));
+        look(&p, 1, token::Ident(sym_f, raw_no));
+        look(&p, 2, token::OpenDelim(Delimiter::Parenthesis));
+        look(&p, 3, token::Ident(sym_x, raw_no));
+        look(&p, 4, token::Colon);
+        look(&p, 5, token::Ident(sym::u32, raw_no));
+        look(&p, 6, token::CloseDelim(Delimiter::Parenthesis));
+        look(&p, 7, token::OpenDelim(Delimiter::Brace));
+        look(&p, 8, token::Ident(sym_x, raw_no));
+        look(&p, 9, token::CloseDelim(Delimiter::Brace));
+        look(&p, 10, token::Ident(kw::Struct, raw_no));
+        look(&p, 11, token::Ident(sym_S, raw_no));
+        look(&p, 12, token::Semi);
+        // Any lookahead past the end of the token stream returns `Eof`.
+        look(&p, 13, token::Eof);
+        look(&p, 14, token::Eof);
+        look(&p, 15, token::Eof);
+        look(&p, 100, token::Eof);
+
+        // Move forward to the first `x`.
+        for _ in 0..3 {
+            p.bump();
+        }
+        look(&p, 0, token::Ident(sym_x, raw_no));
+        look(&p, 1, token::Colon);
+        look(&p, 2, token::Ident(sym::u32, raw_no));
+        look(&p, 3, token::CloseDelim(Delimiter::Parenthesis));
+        look(&p, 4, token::OpenDelim(Delimiter::Brace));
+        look(&p, 5, token::Ident(sym_x, raw_no));
+        look(&p, 6, token::CloseDelim(Delimiter::Brace));
+        look(&p, 7, token::Ident(kw::Struct, raw_no));
+        look(&p, 8, token::Ident(sym_S, raw_no));
+        look(&p, 9, token::Semi);
+        look(&p, 10, token::Eof);
+        look(&p, 11, token::Eof);
+        look(&p, 100, token::Eof);
+
+        // Move forward to the `;`.
+        for _ in 0..9 {
+            p.bump();
+        }
+        look(&p, 0, token::Semi);
+        // Any lookahead past the end of the token stream returns `Eof`.
+        look(&p, 1, token::Eof);
+        look(&p, 100, token::Eof);
+
+        // Move one past the `;`, i.e. past the end of the token stream.
+        p.bump();
+        look(&p, 0, token::Eof);
+        look(&p, 1, token::Eof);
+        look(&p, 100, token::Eof);
+
+        // Bumping after Eof is idempotent.
+        p.bump();
+        look(&p, 0, token::Eof);
+        look(&p, 1, token::Eof);
+        look(&p, 100, token::Eof);
+    });
+}
+
+/// There used to be some buggy behaviour when using `look_ahead` not within
+/// the outermost token stream, which this test covers.
+#[test]
+fn look_ahead_non_outermost_stream() {
+    create_default_session_globals_then(|| {
+        let sym_f = Symbol::intern("f");
+        let sym_x = Symbol::intern("x");
+        #[allow(non_snake_case)]
+        let sym_S = Symbol::intern("S");
+        let raw_no = IdentIsRaw::No;
+
+        let psess = psess();
+        let mut p = string_to_parser(&psess, "mod m { fn f(x: u32) { x } struct S; }".to_string());
+
+        // Move forward to the `fn`, which is not within the outermost token
+        // stream (because it's inside the `mod { ... }`).
+        for _ in 0..3 {
+            p.bump();
+        }
+        look(&p, 0, token::Ident(kw::Fn, raw_no));
+        look(&p, 1, token::Ident(sym_f, raw_no));
+        look(&p, 2, token::OpenDelim(Delimiter::Parenthesis));
+        look(&p, 3, token::Ident(sym_x, raw_no));
+        look(&p, 4, token::Colon);
+        look(&p, 5, token::Ident(sym::u32, raw_no));
+        look(&p, 6, token::CloseDelim(Delimiter::Parenthesis));
+        look(&p, 7, token::OpenDelim(Delimiter::Brace));
+        look(&p, 8, token::Ident(sym_x, raw_no));
+        look(&p, 9, token::CloseDelim(Delimiter::Brace));
+        look(&p, 10, token::Ident(kw::Struct, raw_no));
+        look(&p, 11, token::Ident(sym_S, raw_no));
+        look(&p, 12, token::Semi);
+        look(&p, 13, token::CloseDelim(Delimiter::Brace));
+        // Any lookahead past the end of the token stream returns `Eof`.
+        look(&p, 14, token::Eof);
+        look(&p, 15, token::Eof);
+        look(&p, 100, token::Eof);
+    });
+}
+
+// FIXME(nnethercote) All the output is currently wrong.
+#[test]
+fn debug_lookahead() {
+    create_default_session_globals_then(|| {
+        let psess = psess();
+        let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string());
+
+        // Current position is the `fn`.
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(0)),
+            "Parser {
+    prev_token: Token {
+        kind: Question,
+        span: Span {
+            lo: BytePos(
+                0,
+            ),
+            hi: BytePos(
+                0,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [],
+    approx_token_stream_pos: 1,
+    ..
+}"
+        );
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(7)),
+            "Parser {
+    prev_token: Token {
+        kind: Question,
+        span: Span {
+            lo: BytePos(
+                0,
+            ),
+            hi: BytePos(
+                0,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Ident(
+            \"fn\",
+            No,
+        ),
+        Ident(
+            \"f\",
+            No,
+        ),
+        OpenDelim(
+            Parenthesis,
+        ),
+        Ident(
+            \"x\",
+            No,
+        ),
+        Colon,
+        Ident(
+            \"u32\",
+            No,
+        ),
+        CloseDelim(
+            Parenthesis,
+        ),
+    ],
+    approx_token_stream_pos: 1,
+    ..
+}"
+        );
+        // There are 13 tokens. We request 15, get 14; the last one is `Eof`.
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(15)),
+            "Parser {
+    prev_token: Token {
+        kind: Question,
+        span: Span {
+            lo: BytePos(
+                0,
+            ),
+            hi: BytePos(
+                0,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Ident(
+            \"fn\",
+            No,
+        ),
+        Ident(
+            \"f\",
+            No,
+        ),
+        OpenDelim(
+            Parenthesis,
+        ),
+        Ident(
+            \"x\",
+            No,
+        ),
+        Colon,
+        Ident(
+            \"u32\",
+            No,
+        ),
+        CloseDelim(
+            Parenthesis,
+        ),
+        OpenDelim(
+            Brace,
+        ),
+        Ident(
+            \"x\",
+            No,
+        ),
+        CloseDelim(
+            Brace,
+        ),
+        Ident(
+            \"struct\",
+            No,
+        ),
+        Ident(
+            \"S\",
+            No,
+        ),
+        Semi,
+        Eof,
+    ],
+    approx_token_stream_pos: 1,
+    ..
+}"
+        );
+
+        // Move forward to the second `x`.
+        for _ in 0..8 {
+            p.bump();
+        }
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(1)),
+            "Parser {
+    prev_token: Token {
+        kind: OpenDelim(
+            Brace,
+        ),
+        span: Span {
+            lo: BytePos(
+                13,
+            ),
+            hi: BytePos(
+                14,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Ident(
+            \"x\",
+            No,
+        ),
+    ],
+    approx_token_stream_pos: 9,
+    ..
+}"
+        );
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(4)),
+            "Parser {
+    prev_token: Token {
+        kind: OpenDelim(
+            Brace,
+        ),
+        span: Span {
+            lo: BytePos(
+                13,
+            ),
+            hi: BytePos(
+                14,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Ident(
+            \"x\",
+            No,
+        ),
+        CloseDelim(
+            Brace,
+        ),
+        Ident(
+            \"struct\",
+            No,
+        ),
+        Ident(
+            \"S\",
+            No,
+        ),
+    ],
+    approx_token_stream_pos: 9,
+    ..
+}"
+        );
+
+        // Move two past the final token (the `;`).
+        for _ in 0..6 {
+            p.bump();
+        }
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(3)),
+            "Parser {
+    prev_token: Token {
+        kind: Eof,
+        span: Span {
+            lo: BytePos(
+                27,
+            ),
+            hi: BytePos(
+                28,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Eof,
+    ],
+    approx_token_stream_pos: 15,
+    ..
+}"
+        );
+    });
+}
+
 // This tests that when parsing a string (rather than a file) we don't try
 // and read in a file for a module declaration and just parse a stub.
 // See `recurse_into_file_modules` in the parser.
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 1e5b227aaa9..94321b1dddd 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -209,6 +209,7 @@ impl<'a> Parser<'a> {
         recover_qpath: RecoverQPath,
         recover_return_sign: RecoverReturnSign,
     ) -> PResult<'a, FnRetTy> {
+        let lo = self.prev_token.span;
         Ok(if self.eat(&token::RArrow) {
             // FIXME(Centril): Can we unconditionally `allow_plus`?
             let ty = self.parse_ty_common(
@@ -224,7 +225,10 @@ impl<'a> Parser<'a> {
             // Don't `eat` to prevent `=>` from being added as an expected token which isn't
             // actually expected and could only confuse users
             self.bump();
-            self.dcx().emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span });
+            self.dcx().emit_err(ReturnTypesUseThinArrow {
+                span: self.prev_token.span,
+                suggestion: lo.between(self.token.span),
+            });
             let ty = self.parse_ty_common(
                 allow_plus,
                 AllowCVariadic::No,
@@ -794,8 +798,11 @@ impl<'a> Parser<'a> {
         {
             if self.token.is_keyword(kw::Dyn) {
                 // Account for `&dyn Trait + dyn Other`.
-                self.dcx().emit_err(InvalidDynKeyword { span: self.token.span });
                 self.bump();
+                self.dcx().emit_err(InvalidDynKeyword {
+                    span: self.prev_token.span,
+                    suggestion: self.prev_token.span.until(self.token.span),
+                });
             }
             bounds.push(self.parse_generic_bound()?);
             if allow_plus == AllowPlus::No || !self.eat_plus() {
@@ -861,7 +868,7 @@ impl<'a> Parser<'a> {
         if has_parens {
             // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
             // possibly introducing `GenericBound::Paren(P<GenericBound>)`?
-            self.recover_paren_lifetime(lo, lt.ident.span)?;
+            self.recover_paren_lifetime(lo)?;
         }
         Ok(bound)
     }
@@ -909,16 +916,12 @@ impl<'a> Parser<'a> {
     }
 
     /// Recover on `('lifetime)` with `(` already eaten.
-    fn recover_paren_lifetime(&mut self, lo: Span, lt_span: Span) -> PResult<'a, ()> {
+    fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
         self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
         let span = lo.to(self.prev_token.span);
-        let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(lt_span) {
-            (Some(span), snippet)
-        } else {
-            (None, String::new())
-        };
+        let sugg = errors::RemoveParens { lo, hi: self.prev_token.span };
 
-        self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg, snippet });
+        self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg });
         Ok(())
     }
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index d7513fbad63..1d93cbaddd6 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -290,9 +290,6 @@ passes_export_name =
 passes_extern_main =
     the `main` function cannot be declared in an `extern` block
 
-passes_feature_only_on_nightly =
-    `#![feature]` may not be used on the {$release_channel} release channel
-
 passes_feature_previously_declared =
     feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index a026ff3b13b..58d27d5b4bb 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1493,14 +1493,6 @@ pub struct TraitImplConstStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_feature_only_on_nightly, code = E0554)]
-pub struct FeatureOnlyOnNightly {
-    #[primary_span]
-    pub span: Span,
-    pub release_channel: &'static str,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_unknown_feature, code = E0635)]
 pub struct UnknownFeature {
     #[primary_span]
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 6bdfaf0c908..2c34f477de5 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -936,12 +936,6 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     let declared_lib_features = &tcx.features().declared_lib_features;
     let mut remaining_lib_features = FxIndexMap::default();
     for (feature, span) in declared_lib_features {
-        if !tcx.sess.opts.unstable_features.is_nightly_build() {
-            tcx.dcx().emit_err(errors::FeatureOnlyOnNightly {
-                span: *span,
-                release_channel: env!("CFG_RELEASE_CHANNEL"),
-            });
-        }
         if remaining_lib_features.contains_key(&feature) {
             // Warn if the user enables a lib feature multiple times.
             tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature });
diff --git a/compiler/rustc_query_system/src/cache.rs b/compiler/rustc_query_system/src/cache.rs
index 6e862db0b25..d8a5bdba7b8 100644
--- a/compiler/rustc_query_system/src/cache.rs
+++ b/compiler/rustc_query_system/src/cache.rs
@@ -40,7 +40,7 @@ impl<Key: Eq + Hash, Value: Clone> Cache<Key, Value> {
     }
 }
 
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Debug, Clone, Eq, PartialEq)]
 pub struct WithDepNode<T> {
     dep_node: DepNodeIndex,
     cached_value: T,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index ffd495aa985..e3917acce65 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -819,7 +819,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
                 self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
             }
-            ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => {
+            ResolutionError::AttemptToUseNonConstantValueInConstant {
+                ident,
+                suggestion,
+                current,
+                type_span,
+            } => {
                 // let foo =...
                 //     ^^^ given this Span
                 // ------- get this Span to have an applicable suggestion
@@ -836,13 +841,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
                 let ((with, with_label), without) = match sp {
                     Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
-                        let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32)));
+                        let sp = sp
+                            .with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
+                            .until(ident.span);
                         (
                         (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
                                 span: sp,
-                                ident,
                                 suggestion,
                                 current,
+                                type_span,
                             }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
                             None,
                         )
@@ -1985,12 +1992,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             if let Some(candidate) = candidates.get(0) {
                 let path = {
                     // remove the possible common prefix of the path
-                    let start_index = (0..failed_segment_idx)
-                        .find(|&i| path[i].ident != candidate.path.segments[i].ident)
+                    let len = candidate.path.segments.len();
+                    let start_index = (0..=failed_segment_idx.min(len - 1))
+                        .find(|&i| path[i].ident.name != candidate.path.segments[i].ident.name)
                         .unwrap_or_default();
-                    let segments = (start_index..=failed_segment_idx)
-                        .map(|s| candidate.path.segments[s].clone())
-                        .collect();
+                    let segments =
+                        (start_index..len).map(|s| candidate.path.segments[s].clone()).collect();
                     Path { segments, span: Span::default(), tokens: None }
                 };
                 (
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 0620f3d709e..097f4af05c3 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -240,16 +240,18 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(
+#[multipart_suggestion(
     resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion,
-    code = "{suggestion} {ident}",
-    applicability = "maybe-incorrect"
+    style = "verbose",
+    applicability = "has-placeholders"
 )]
 pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> {
-    #[primary_span]
+    // #[primary_span]
+    #[suggestion_part(code = "{suggestion} ")]
     pub(crate) span: Span,
-    pub(crate) ident: Ident,
     pub(crate) suggestion: &'a str,
+    #[suggestion_part(code = ": /* Type */")]
+    pub(crate) type_span: Option<Span>,
     pub(crate) current: &'a str,
 }
 
@@ -1089,8 +1091,8 @@ pub(crate) struct ToolWasAlreadyRegistered {
 #[derive(Diagnostic)]
 #[diag(resolve_tool_only_accepts_identifiers)]
 pub(crate) struct ToolOnlyAcceptsIdentifiers {
-    #[label]
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
     pub(crate) tool: Symbol,
 }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 7d531385e21..f1934ff184b 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1178,21 +1178,41 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             if let Some(span) = finalize {
                                 let (span, resolution_error) = match item {
                                     None if rib_ident.as_str() == "self" => (span, LowercaseSelf),
-                                    None => (
-                                        rib_ident.span,
-                                        AttemptToUseNonConstantValueInConstant(
-                                            original_rib_ident_def,
-                                            "const",
-                                            "let",
-                                        ),
-                                    ),
+                                    None => {
+                                        // If we have a `let name = expr;`, we have the span for
+                                        // `name` and use that to see if it is followed by a type
+                                        // specifier. If not, then we know we need to suggest
+                                        // `const name: Ty = expr;`. This is a heuristic, it will
+                                        // break down in the presence of macros.
+                                        let sm = self.tcx.sess.source_map();
+                                        let type_span = match sm.span_look_ahead(
+                                            original_rib_ident_def.span,
+                                            ":",
+                                            None,
+                                        ) {
+                                            None => {
+                                                Some(original_rib_ident_def.span.shrink_to_hi())
+                                            }
+                                            Some(_) => None,
+                                        };
+                                        (
+                                            rib_ident.span,
+                                            AttemptToUseNonConstantValueInConstant {
+                                                ident: original_rib_ident_def,
+                                                suggestion: "const",
+                                                current: "let",
+                                                type_span,
+                                            },
+                                        )
+                                    }
                                     Some((ident, kind)) => (
                                         span,
-                                        AttemptToUseNonConstantValueInConstant(
+                                        AttemptToUseNonConstantValueInConstant {
                                             ident,
-                                            "let",
-                                            kind.as_str(),
-                                        ),
+                                            suggestion: "let",
+                                            current: kind.as_str(),
+                                            type_span: None,
+                                        },
                                     ),
                                 };
                                 self.report_error(span, resolution_error);
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7cb5a3fb2fd..3dcb83d65b0 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -236,11 +236,12 @@ enum ResolutionError<'a> {
     /// Error E0434: can't capture dynamic environment in a fn item.
     CannotCaptureDynamicEnvironmentInFnItem,
     /// Error E0435: attempt to use a non-constant value in a constant.
-    AttemptToUseNonConstantValueInConstant(
-        Ident,
-        /* suggestion */ &'static str,
-        /* current */ &'static str,
-    ),
+    AttemptToUseNonConstantValueInConstant {
+        ident: Ident,
+        suggestion: &'static str,
+        current: &'static str,
+        type_span: Option<Span>,
+    },
     /// Error E0530: `X` bindings cannot shadow `Y`s.
     BindingShadowsSomethingUnacceptable {
         shadowing_binding: PatternSource,
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 41c99f7edee..e748d1ff47b 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2620,7 +2620,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         // This is the location used by the `rust-src` `rustup` component.
         let mut candidate = sysroot.join("lib/rustlib/src/rust");
         if let Ok(metadata) = candidate.symlink_metadata() {
-            // Replace the symlink rustbuild creates, with its destination.
+            // Replace the symlink bootstrap creates, with its destination.
             // We could try to use `fs::canonicalize` instead, but that might
             // produce unnecessarily verbose path.
             if metadata.file_type().is_symlink() {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 7421cae65e4..8fd1876ff1d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1687,6 +1687,8 @@ options! {
         (default: no)"),
     dump_mir_dir: String = ("mir_dump".to_string(), parse_string, [UNTRACKED],
         "the directory the MIR is dumped into (default: `mir_dump`)"),
+    dump_mir_exclude_alloc_bytes: bool = (false, parse_bool, [UNTRACKED],
+        "exclude the raw bytes of allocations when dumping MIR (used in tests) (default: no)"),
     dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
         "exclude the pass number when dumping MIR (used in tests) (default: no)"),
     dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
@@ -1709,6 +1711,8 @@ options! {
         "emit a section containing stack size metadata (default: no)"),
     emit_thin_lto: bool = (true, parse_bool, [TRACKED],
         "emit the bc module with thin LTO info (default: yes)"),
+    enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
+        "enforce the type length limit when monomorphizing instances in codegen"),
     export_executable_symbols: bool = (false, parse_bool, [TRACKED],
         "export symbols from executables, as if they were dynamic libraries"),
     external_clangrt: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 7b5abcf4513..7c3553b60fd 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -466,7 +466,6 @@ impl RustcInternal for Abi {
             Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt,
             Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt,
             Abi::CCmseNonSecureCall => rustc_target::spec::abi::Abi::CCmseNonSecureCall,
-            Abi::Wasm => rustc_target::spec::abi::Abi::Wasm,
             Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind },
             Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic,
             Abi::RustCall => rustc_target::spec::abi::Abi::RustCall,
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 9382460d6d4..ef2eb7d52ea 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -909,7 +909,6 @@ impl<'tcx> Stable<'tcx> for rustc_target::spec::abi::Abi {
             abi::Abi::AvrInterrupt => Abi::AvrInterrupt,
             abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt,
             abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall,
-            abi::Abi::Wasm => Abi::Wasm,
             abi::Abi::System { unwind } => Abi::System { unwind },
             abi::Abi::RustIntrinsic => Abi::RustIntrinsic,
             abi::Abi::RustCall => Abi::RustCall,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index af56f4e5141..2fe7c951793 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -2072,9 +2072,11 @@ symbols! {
         write_str,
         write_via_move,
         writeln_macro,
+        x86_amx_intrinsics,
         x87_reg,
         xer,
         xmm_reg,
+        xop_target_feature,
         yeet_desugar_details,
         yeet_expr,
         yes,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 8058130f441..9f13c195e4c 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -1,6 +1,6 @@
 use crate::abi::{self, Abi, Align, FieldsShape, Size};
 use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
-use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt};
+use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -854,7 +854,8 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             return Ok(());
         }
 
-        match &cx.target_spec().arch[..] {
+        let spec = cx.target_spec();
+        match &spec.arch[..] {
             "x86" => {
                 let flavor = if let spec::abi::Abi::Fastcall { .. }
                 | spec::abi::Abi::Vectorcall { .. } = abi
@@ -901,9 +902,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "sparc" => sparc::compute_abi_info(cx, self),
             "sparc64" => sparc64::compute_abi_info(cx, self),
             "nvptx64" => {
-                if cx.target_spec().adjust_abi(cx, abi, self.c_variadic)
-                    == spec::abi::Abi::PtxKernel
-                {
+                if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::PtxKernel {
                     nvptx64::compute_ptx_kernel_abi_info(cx, self)
                 } else {
                     nvptx64::compute_abi_info(self)
@@ -912,13 +911,14 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "hexagon" => hexagon::compute_abi_info(self),
             "xtensa" => xtensa::compute_abi_info(cx, self),
             "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
-            "wasm32" | "wasm64" => {
-                if cx.target_spec().adjust_abi(cx, abi, self.c_variadic) == spec::abi::Abi::Wasm {
+            "wasm32" => {
+                if spec.os == "unknown" && cx.wasm_c_abi_opt() == WasmCAbi::Legacy {
                     wasm::compute_wasm_abi_info(self)
                 } else {
                     wasm::compute_c_abi_info(cx, self)
                 }
             }
+            "wasm64" => wasm::compute_c_abi_info(cx, self),
             "bpf" => bpf::compute_abi_info(self),
             arch => {
                 return Err(AdjustForForeignAbiError::Unsupported {
diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs
index bf51bb4bf82..0d61345a70e 100644
--- a/compiler/rustc_target/src/spec/abi/mod.rs
+++ b/compiler/rustc_target/src/spec/abi/mod.rs
@@ -48,7 +48,6 @@ pub enum Abi {
     AvrInterrupt,
     AvrNonBlockingInterrupt,
     CCmseNonSecureCall,
-    Wasm,
     System {
         unwind: bool,
     },
@@ -123,7 +122,6 @@ const AbiDatas: &[AbiData] = &[
     AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" },
     AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" },
     AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" },
-    AbiData { abi: Abi::Wasm, name: "wasm" },
     AbiData { abi: Abi::System { unwind: false }, name: "system" },
     AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" },
     AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
@@ -149,6 +147,9 @@ pub fn lookup(name: &str) -> Result<Abi, AbiUnsupported> {
         "riscv-interrupt-u" => AbiUnsupported::Reason {
             explain: "user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314",
         },
+        "wasm" => AbiUnsupported::Reason {
+            explain: "non-standard wasm ABI is no longer supported",
+        },
 
         _ => AbiUnsupported::Unrecognized,
 
@@ -241,10 +242,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
             feature: sym::abi_c_cmse_nonsecure_call,
             explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
         }),
-        "wasm" => Err(AbiDisabled::Unstable {
-            feature: sym::wasm_abi,
-            explain: "wasm ABI is experimental and subject to change",
-        }),
         _ => Err(AbiDisabled::Unrecognized),
     }
 }
@@ -287,16 +284,15 @@ impl Abi {
             AvrInterrupt => 23,
             AvrNonBlockingInterrupt => 24,
             CCmseNonSecureCall => 25,
-            Wasm => 26,
             // Cross-platform ABIs
-            System { unwind: false } => 27,
-            System { unwind: true } => 28,
-            RustIntrinsic => 29,
-            RustCall => 30,
-            Unadjusted => 31,
-            RustCold => 32,
-            RiscvInterruptM => 33,
-            RiscvInterruptS => 34,
+            System { unwind: false } => 26,
+            System { unwind: true } => 27,
+            RustIntrinsic => 28,
+            RustCall => 29,
+            Unadjusted => 30,
+            RustCold => 31,
+            RiscvInterruptM => 32,
+            RiscvInterruptS => 33,
         };
         debug_assert!(
             AbiDatas
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 81ada30a594..607eeac7ccd 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2608,22 +2608,8 @@ impl DerefMut for Target {
 
 impl Target {
     /// Given a function ABI, turn it into the correct ABI for this target.
-    pub fn adjust_abi<C>(&self, cx: &C, abi: Abi, c_variadic: bool) -> Abi
-    where
-        C: HasWasmCAbiOpt,
-    {
+    pub fn adjust_abi(&self, abi: Abi, c_variadic: bool) -> Abi {
         match abi {
-            Abi::C { .. } => {
-                if self.arch == "wasm32"
-                    && self.os == "unknown"
-                    && cx.wasm_c_abi_opt() == WasmCAbi::Legacy
-                {
-                    Abi::Wasm
-                } else {
-                    abi
-                }
-            }
-
             // On Windows, `extern "system"` behaves like msvc's `__stdcall`.
             // `__stdcall` only applies on x86 and on non-variadic functions:
             // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
@@ -2676,7 +2662,6 @@ impl Target {
             Msp430Interrupt => self.arch == "msp430",
             RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]),
             AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
-            Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
             Thiscall { .. } => self.arch == "x86",
             // On windows these fall-back to platform native calling convention (C) when the
             // architecture is not supported.
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
index 4e2964174f9..f37781c3f63 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
@@ -16,10 +16,10 @@ pub fn target() -> Target {
         // correctly, we do too.
         llvm_target: macos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 macOS (11.0+, Big Sur+)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
index 20655689772..11a39c26e9d 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
         // MACH-O commands, so we do too.
         llvm_target: ios_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 iOS".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
index 4c008f7985e..85c40ec60c4 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: mac_catalyst_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Apple Catalyst on ARM64".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
index 4a63abdf541..703b886cc19 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
         // MACH-O commands, so we do too.
         llvm_target: ios_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Apple iOS Simulator on ARM64".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
index 3310e6c9e8a..e97ad11cdf6 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: tvos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 tvOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
index b901c663afa..8bfa9c8e8b7 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: tvos_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 tvOS Simulator".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
index a00a97a133f..6d66299d6d9 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-apple-watchos".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Apple WatchOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
index e2f80b7b7a8..9675a950d5d 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
         // MACH-O commands, so we do too.
         llvm_target: watchos_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Apple WatchOS Simulator".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
index 88115b81fa5..df389fe34bd 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64_be-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Linux (big-endian)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
index b89c2841dae..10a8e3e4df8 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
@@ -8,10 +8,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64_be-unknown-linux-gnu_ilp32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Linux (big-endian, ILP32 ABI)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
index d9164f8b052..ba646cd6065 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64_be-unknown-netbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 NetBSD (big-endian)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs
index 168f6ad1ac2..1c2273bb3a1 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 SOLID with TOPPERS/ASP3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
index e9fa482bff1..3f0072c00c1 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-linux-android".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Android".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
index 7e7e202b112..1ba4fbb3d25 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Nintendo Switch, Horizon".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs
index 2cc417ea830..070460538c7 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-pc-windows-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 MinGW (Windows 10+), LLVM ABI".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
index a5e7dda5fb8..f4e2ee44805 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs
@@ -8,10 +8,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Windows MSVC".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs
index 81c9d5927fa..b10f1c7592e 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-freebsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 FreeBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs
index d740f0b7c97..f84853fbb19 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-fuchsia".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Fuchsia".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs
index a466fa05516..55cb0b8f2ee 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-hermit".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Hermit".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         arch: "aarch64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs
index 6f253c2a223..7f05358e016 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs
@@ -12,10 +12,10 @@ pub fn target() -> Target {
         // so we still pass Solaris to it
         llvm_target: "aarch64-unknown-solaris2.11".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 illumos".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
index 0c4bac0e129..1a45c2c5c05 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Linux (kernel 4.1, glibc 2.17+)".into()),
+            tier: Some(1),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
index e202ce2f57f..851366b7647 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-linux-gnu_ilp32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Linux (ILP32 ABI)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
index 4a82423bb63..6b4a422a474 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
@@ -15,10 +15,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 Linux with musl 1.2.3".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
index 3d357bcf3f2..5924e4f5757 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
         // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
         llvm_target: "aarch64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 OpenHarmony".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs
index ac26aa82271..0069d5431f8 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-netbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 NetBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs
index 21706aa0b5d..169468f2e24 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs
@@ -32,10 +32,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARM64, hardfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
index 4f04a7816ce..222d5651b52 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs
@@ -26,10 +26,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARM64, softfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
index 8e448a2fa9a..0e5a0b9b9a5 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-unknown".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 QNX Neutrino 7.1 RTOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         // from: https://llvm.org/docs/LangRef.html#data-layout
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs
index b51cddafb1a..e16991af4e6 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-openbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 OpenBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs
index 544709cffe6..e59b38a3e41 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-redox".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 RedoxOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
index 285c5e79cf0..5ae2d68332c 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 TEEOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs
index de4a56ae03d..429303170b6 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "aarch64-unknown-windows".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64 UEFI".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs
index 50064e673b3..df1b75272b1 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs
@@ -9,9 +9,9 @@ pub fn target() -> Target {
         llvm_target: "aarch64-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs
index 026b30e9eb7..41f7532ecdb 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs
@@ -5,9 +5,9 @@ pub fn target() -> Target {
         llvm_target: "aarch64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
index 3ca8c9969c2..2c76f4736de 100644
--- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: watchos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Arm Apple WatchOS 64-bit with 32-bit pointers".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
index 90be518638e..6f28f5d0543 100644
--- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
@@ -16,10 +16,10 @@ pub fn target() -> Target {
         // correctly, we do too.
         llvm_target: macos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64e Apple Darwin".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
index 56470d29eae..1590ae9679d 100644
--- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
         // MACH-O commands, so we do too.
         llvm_target: ios_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("ARM64e Apple iOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
index aedfb881024..21cb38868fb 100644
--- a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "arm64ec-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Arm64EC Windows MSVC".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs
index 12c6388a97b..a22bcef4757 100644
--- a/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_linux_androideabi.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "arm-linux-androideabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv6 Android".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs
index 8abf7dd5323..8ff272e786d 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabi.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "arm-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv6 Linux (kernel 3.2, glibc 2.17)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
index 922f51fd60d..e3e2f4cd05c 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "arm-unknown-linux-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs
index 3c01c86c7d5..f958b89358b 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabi.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
         // support the "musleabi" value.
         llvm_target: "arm-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv6 Linux with musl 1.2.3".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs
index 5be5bb03979..98093fdc003 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
         // doesn't support the "musleabihf" value.
         llvm_target: "arm-unknown-linux-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv6 Linux with musl 1.2.3, hardfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs
index f95ec8c78dd..b56f311793a 100644
--- a/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armeb_unknown_linux_gnueabi.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armeb-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Arm BE8 the default Arm big-endian architecture since Armv6".into()),
+            tier: Some(3),
+            host_tools: None, // ?
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
index d5ee10dbfc4..df32b74f6d9 100644
--- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armebv7r-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare Armv7-R, Big Endian".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
index 2f86506e2d0..063038c8012 100644
--- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armebv7r-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare Armv7-R, Big Endian, hardfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs
index 42d165a6ca4..f873fb0d349 100644
--- a/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv4t_none_eabi.rs
@@ -15,10 +15,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv4t-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare Armv4T".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "arm".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs
index d12bc241d06..18f327bc87f 100644
--- a/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv4t_unknown_linux_gnueabi.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv4t-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv4T Linux".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs
index 512a175f2c9..1fbe4b89ea1 100644
--- a/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv5te_none_eabi.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv5te-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare Armv5TE".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "arm".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs
index 6b31d0ee25f..12368644837 100644
--- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_gnueabi.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv5te-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv5TE Linux (kernel 4.4, glibc 2.23)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs
index ea14a2ec252..ccbc1e36dde 100644
--- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_musleabi.rs
@@ -8,10 +8,10 @@ pub fn target() -> Target {
         // doesn't support the "musleabihf" value.
         llvm_target: "armv5te-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv5TE Linux with musl 1.2.3".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs
index e2ab803576a..d88b88333b5 100644
--- a/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv5te_unknown_linux_uclibceabi.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv5te-unknown-linux-uclibcgnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv5TE Linux with uClibc".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
index 04f35178828..24e9d1e0394 100644
--- a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv6-unknown-freebsd-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv6 FreeBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
index ca4d42ebbe8..62e328b9cbd 100644
--- a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv6-unknown-netbsdelf-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv6 NetBSD w/hard-float".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs
index 9a88277b063..bcdad0a55b3 100644
--- a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs
+++ b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv6k-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs
index e798ef47354..8f6a58a1b49 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs
@@ -14,10 +14,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-none-linux-android".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Android".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
index 0730a423f72..a9b5172385b 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
@@ -14,10 +14,12 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv7a-vita-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some(
+                "Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)".into(),
+            ),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
index 017b126129c..3a16bbe95db 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-freebsd-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A FreeBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs
index 2be263d6d9c..8a4ba271456 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabi.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Linux (kernel 4.15, glibc 2.27)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs
index 8a80a623b1d..a217a2daeb3 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs
index ad4ebed74e7..96459a5137f 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabi.rs
@@ -12,10 +12,10 @@ pub fn target() -> Target {
         // support the "musleabi" value.
         llvm_target: "armv7-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Linux with musl 1.2.3".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs
index ba7b62bc5eb..6c878141fd4 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
         // doesn't support the "musleabihf" value.
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Linux with musl 1.2.3, hardfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs
index 489aad7845d..bffc51d9b7b 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
         // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
         llvm_target: "armv7-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A OpenHarmony".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs
index fdf46101d25..9dc1221287d 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabi.rs
@@ -8,10 +8,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Linux with uClibc, softfloat".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs
index 36bc9548209..01a1468d3a8 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs
@@ -8,10 +8,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Linux with uClibc, hardfloat".into()),
+            tier: Some(3),
+            host_tools: None, // ?
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
index 2dc4d9b835b..a2391503ff8 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-netbsdelf-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A NetBSD w/hard-float".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs
index 89469f01c3a..7d60ec1b64d 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A for VxWorks".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
index ffdeba50df2..76d4653931b 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7a-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Arm SOLID with TOPPERS/ASP3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
index cbcf223daf6..d2b4d46adac 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7a-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Arm SOLID with TOPPERS/ASP3, hardfloat".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs
index 3373e677c4a..b544c404f3f 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabi.rs
@@ -33,10 +33,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7a-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare Armv7-A".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs
index 12844a8e582..aebb7e667bc 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs
@@ -25,10 +25,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7a-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare Armv7-A, hardfloat".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
index 5c675c22ef5..e876c567b09 100644
--- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7k-apple-watchos".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Apple WatchOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs
index d5213234339..b3246dc7928 100644
--- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabi.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7r-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-R".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs
index 7c39d2d38de..9ac500d7ffe 100644
--- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7r-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-R, hardfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
index 4dd475e3a82..11608794932 100644
--- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: ios_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Armv7-A Apple-A6 Apple iOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
index 17fdd496302..ee940c3a76a 100644
--- a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv8r-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare Armv8-R, hardfloat".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs
index 470674372fd..8cddb6fe005 100644
--- a/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/bpfeb_unknown_none.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "bpfeb".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("BPF (big endian)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         data_layout: "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         pointer_width: 64,
diff --git a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs
index 3e3202df17e..d070aa0ec44 100644
--- a/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/bpfel_unknown_none.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "bpfel".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("BPF (little endian)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         pointer_width: 64,
diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs
index 120c75f528a..e8a0b465e15 100644
--- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs
+++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2.rs
@@ -6,7 +6,12 @@ pub fn target() -> Target {
     Target {
         //https://github.com/llvm/llvm-project/blob/8b76aea8d8b1b71f6220bc2845abc749f18a19b7/clang/lib/Basic/Targets/CSKY.h
         llvm_target: "csky-unknown-linux-gnuabiv2".into(),
-        metadata: crate::spec::TargetMetadata { description:None, tier: None, host_tools: None, std: None },
+        metadata: crate::spec::TargetMetadata {
+            description: Some("C-SKY abiv2 Linux (little endian)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true)
+        },
         pointer_width: 32,
         data_layout: "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32".into(),
         arch: "csky".into(),
diff --git a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs
index 2856e94ea4a..99330ddc318 100644
--- a/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs
+++ b/compiler/rustc_target/src/spec/targets/csky_unknown_linux_gnuabiv2hf.rs
@@ -6,7 +6,12 @@ pub fn target() -> Target {
     Target {
         //https://github.com/llvm/llvm-project/blob/8b76aea8d8b1b71f6220bc2845abc749f18a19b7/clang/lib/Basic/Targets/CSKY.h
         llvm_target: "csky-unknown-linux-gnuabiv2".into(),
-        metadata: crate::spec::TargetMetadata { description:None, tier: None, host_tools: None, std: None },
+        metadata: crate::spec::TargetMetadata {
+            description: Some("C-SKY abiv2 Linux, hardfloat (little endian)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true)
+        },
         pointer_width: 32,
         data_layout: "e-m:e-S32-p:32:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:32-v128:32:32-a:0:32-Fi32-n32".into(),
         arch: "csky".into(),
diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs
index 003d35ebeb4..bd539799029 100644
--- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs
@@ -16,10 +16,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "hexagon-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Hexagon Linux with musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: concat!(
diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs
index 8750e0ee85f..cefd0bf6d67 100644
--- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_none_elf.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "hexagon-unknown-none-elf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare Hexagon (v60+, HVX)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: concat!(
diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
index c03a0974bc1..b1b2b6cdffa 100644
--- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
         // MACH-O commands, so we do too.
         llvm_target: ios_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit x86 iOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
index 290ed81ad45..6c80ab6994d 100644
--- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
+++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i586-pc-unknown".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit x86 QNX Neutrino 7.0 RTOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs
index 73949c7bdc4..de42549b7f8 100644
--- a/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/i586_unknown_netbsd.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i586-unknown-netbsdelf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit x86, resricted to Pentium".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
index aea6a1ac4ec..02f6bec4692 100644
--- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
@@ -17,10 +17,10 @@ pub fn target() -> Target {
         // While ld64 doesn't understand i686, LLVM does.
         llvm_target: macos_llvm_target(Arch::I686).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit macOS (10.12+, Sierra+)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs
index 585aad10c57..fc313e575be 100644
--- a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs
@@ -16,10 +16,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-linux-android".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit x86 Android".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
index 66e09416dde..4b0f4bf3ecd 100644
--- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
@@ -18,10 +18,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-pc-windows-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit MinGW (Windows 10+)".into()),
+            tier: Some(1),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs
index 7a2d28aec9c..5bb08201429 100644
--- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnullvm.rs
@@ -17,10 +17,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-pc-windows-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit x86 MinGW (Windows 10+), LLVM ABI".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs
index 5826906e9d8..cce21fcacb1 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-unknown-freebsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit FreeBSD".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs
index 5f66911b39a..84ef00f06c8 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-unknown-haiku".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit Haiku".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
index a67105f24ca..ad8c0f7f582 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-unknown-hurd-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit GNU/Hurd".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs
index 1d4916cabfd..5584435a0ad 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit Linux (kernel 3.2, glibc 2.17+)".into()),
+            tier: Some(1),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs
index c3b9b71802b..d1ab1f73b51 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs
@@ -24,10 +24,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit Linux with musl 1.2.3".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs
index 87eba1fb856..255148fca9a 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-unknown-netbsdelf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("NetBSD/i386 with SSE2".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs
index 0436f39f5b1..d6df801234c 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-unknown-openbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit OpenBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs
index 8665a7ca61a..b92fc2e759a 100644
--- a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs
@@ -79,10 +79,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-unknown-windows-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit UEFI".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs
index 77dcd645728..851bea80fb8 100644
--- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_gnu.rs
@@ -18,9 +18,9 @@ pub fn target() -> Target {
         llvm_target: "i686-pc-windows-gnu".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs
index b3830226267..28bd2aae8e7 100644
--- a/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_uwp_windows_msvc.rs
@@ -9,9 +9,9 @@ pub fn target() -> Target {
         llvm_target: "i686-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
index ae1a44e44a8..cd488d0532c 100644
--- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
@@ -22,10 +22,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "i686-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit Windows 7 support".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs
index e4d0b674cc4..973c75eeca6 100644
--- a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
         llvm_target: "i686-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
index 3e88180012e..6f0bb449c16 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
index c45bc438350..19b04607f0e 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "loongarch64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("LoongArch64 Linux (LP64D ABI) with musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
index 69533e82c3c..744ffff721f 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
@@ -6,9 +6,9 @@ pub fn target() -> Target {
         llvm_target: "loongarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
index bc4c5bcde5e..a382e7a53fb 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
@@ -6,9 +6,9 @@ pub fn target() -> Target {
         llvm_target: "loongarch64-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
index abd07ef9bdc..7cff0efd112 100644
--- a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "m68k-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Motorola 680x0 Linux".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs
index 9df7b2b670f..c3235bf994f 100644
--- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs
@@ -14,10 +14,10 @@ pub fn target() -> Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS64 for OpenWrt Linux musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs
index e9de4a5c260..cdf4ffb7f9e 100644
--- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mips64-unknown-linux-gnuabi64".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
index 48443717b19..463f7dc47f7 100644
--- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS64 Linux, N64 ABI, musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs
index 515473fbabc..ad77a02c063 100644
--- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mips64el-unknown-linux-gnuabi64".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS64 Linux, N64 ABI (kernel 4.4, glibc 2.23)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
index e6b998746e6..83f5c7ea37d 100644
--- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64el-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS64 Linux, N64 ABI, musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs
index 3616ea60304..0bdfd6ee6b0 100644
--- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_gnu.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mips-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS Linux (kernel 4.4, glibc 2.23)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs
index b47bc0d3005..8e27c9936c5 100644
--- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_musl.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mips-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS Linux with musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs
index 117d74f2d25..852e1d9376d 100644
--- a/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/targets/mips_unknown_linux_uclibc.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mips-unknown-linux-uclibc".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS Linux with uClibc".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs
index fafe1493538..9d3f4d9f795 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psp.rs
@@ -12,10 +12,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-sony-psp".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS (LE) Sony PlatStation Portable (PSP)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs
index 9f37b0edc17..c0b99a68b0d 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-sony-psx".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS (LE) Sony PlayStation 1 (PSX)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs
index e65480e355b..8fe4548a3ad 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_gnu.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS (little endian) Linux (kernel 4.4, glibc 2.23)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs
index ed98f53a2b2..43914a23308 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_musl.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS (little endian) Linux with musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs
index dc6807509cb..6150654c081 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_linux_uclibc.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-linux-uclibc".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("MIPS (LE) Linux with uClibc".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs
index 8e5cd30a54f..03501aa76a8 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_netbsd.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-netbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit MIPS (LE), requires mips32 cpu support".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs
index b5948b4d35c..81aac3ce0b8 100644
--- a/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsel_unknown_none.rs
@@ -8,10 +8,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-none".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare MIPS (LE) softfloat".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs
index dbb143b7319..2ed520e9f48 100644
--- a/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6_unknown_linux_gnu.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsisa32r6-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit MIPS Release 6 Big Endian".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs
index f5fff6bec1c..de30c5b35b7 100644
--- a/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsisa32r6el_unknown_linux_gnu.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsisa32r6el-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit MIPS Release 6 Little Endian".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs
index ed236cca1bb..4178a991e14 100644
--- a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit MIPS Release 6 Big Endian".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs
index bbdc5b95ad1..8e50373bd12 100644
--- a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit MIPS Release 6 Little Endian".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
index 2b022a4a558..de476741def 100644
--- a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "msp430-none-elf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("16-bit MSP430 microcontrollers".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 16,
         data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".into(),
diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
index 0b0b31b503b..15156fbcfc9 100644
--- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
         data_layout: "e-i64:64-i128:128-v16:16-v32:32-n16:32:64".into(),
         llvm_target: "nvptx64-nvidia-cuda".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("--emit=asm generates PTX code that runs on NVIDIA GPUs".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
 
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
index 481df71c1a6..bda43e7a2b0 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-ibm-aix".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit AIX (7.2 and newer)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "E-m:a-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
index b1b981823b8..6eb5bba0fcd 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-freebsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("PPC64 FreeBSD (ELFv1 and ELFv2)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-Fn32-i64:64-n32:64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
index ac10630d944..53b84479a49 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("PowerPC Linux (kernel 3.2, glibc 2.17)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
index 663f06cf0c6..0d0484dd174 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit PowerPC Linux with musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
index 5611352c951..2922c921e17 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-openbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("OpenBSD/powerpc64".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-Fn32-i64:64-n32:64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
index 22b45042aa6..dd2ec274207 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
@@ -12,9 +12,9 @@ pub fn target() -> Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
index 812b5928966..ea295cf169e 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64le-unknown-freebsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("PPC64LE FreeBSD".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-Fn32-i64:64-n32:64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
index e3c4b3b585c..dc70bd238a7 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("PPC64LE Linux (kernel 3.10, glibc 2.17)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
index 497a40ade81..dbfbd69b95b 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64le-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit PowerPC Linux with musl 1.2.3, Little Endian".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs
index 194bb0566f1..2f7acccfae8 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs
@@ -14,10 +14,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-freebsd13.0".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("PowerPC FreeBSD".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs
index b88b2fbf809..2ecafbb08bc 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("PowerPC Linux (kernel 3.2, glibc 2.17)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs
index b09c4cd21e0..04b2309fdc8 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("PowerPC SPE Linux".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs
index 67b19e90489..108e468eb66 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("PowerPC Linux with musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs
index c592cd3f6fd..3ee6cd46c85 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_netbsd.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-netbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("NetBSD 32-bit powerpc systems".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs
index a17f437e064..f00ee960413 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_openbsd.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
         llvm_target: "powerpc-unknown-openbsd".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs
index 91925ce151d..5d107d6e60e 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
         llvm_target: "powerpc-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs
index 7640feb28e3..aea525a6912 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks_spe.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
index 7e607574241..e425d6a3f3f 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv32-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V Linux (kernel 5.4, glibc 2.33)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
index a46b1bb6588..409b6b22f1c 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs
@@ -6,10 +6,12 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv32-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some(
+                "RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches".into(),
+            ),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
index 87eebbe8708..631a31edeb5 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare RISC-V (RV32I ISA)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
index 186f8105df5..726778aca0d 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
index 962fcd0eb99..5fa3858e857 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
@@ -6,9 +6,9 @@ pub fn target() -> Target {
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
index 9acf6a3b5a0..2022873d05c 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare RISC-V (RV32IMA ISA)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
index 1e1356910d9..386e3a38f97 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V ESP-IDF".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
index 705bc17892a..7ced37e1535 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare RISC-V (RV32IMAC ISA)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
index 80b6e6077b2..cd50a9e60c3 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V Xous (RV32IMAC ISA)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs
index 6c660793777..3661e38e7b1 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V ESP-IDF".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs
index f4a0cd1c51e..95466090891 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare RISC-V (RV32IMAFC ISA)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
index cee6fd32dd6..d52dc8f96ca 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V ESP-IDF".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
index 5378c132df1..ff993197846 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
         llvm_target: "riscv32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare RISC-V (RV32IMC ISA)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "riscv32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
index 27629199ea5..2dfaf8a2033 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-linux-android".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V 64-bit Android".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs
index 37c360e6761..1fd6a4b38dc 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-freebsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V FreeBSD".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
index a600ee76566..5c3f525966e 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-fuchsia".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V Fuchsia".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs
index 63c06a97223..f11128cfcb6 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_hermit.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-hermit".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V Hermit".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         arch: "riscv64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
index 199ffc1c139..308c995297b 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V Linux (kernel 4.20, glibc 2.29)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
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 f8b5ceee8b4..3e575fdd528 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
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V Linux (kernel 4.20, musl 1.2.3)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs
index 9dbe01f4598..65781f5af5c 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_netbsd.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-netbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("RISC-V NetBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
index 9f128d07a99..a75f8969a73 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_none_elf.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare RISC-V (RV64IMAFDC ISA)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         llvm_target: "riscv64".into(),
         pointer_width: 64,
diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs
index 29919a16078..5bdbda773b1 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_openbsd.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-openbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("OpenBSD/riscv64".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
index 1ab6aebcea9..ba9a10e6633 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         llvm_target: "riscv64".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare RISC-V (RV64IMAC ISA)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         arch: "riscv64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
index be68c5b1c88..b0dd0eb612e 100644
--- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
@@ -19,10 +19,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "s390x-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("S390x Linux (kernel 3.2, glibc 2.17)".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
index 619e83ce620..3976233819c 100644
--- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
@@ -20,10 +20,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "s390x-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("S390x Linux (kernel 3.2, musl 1.2.3)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs
index 77c9b4f996a..eeb7eebfe50 100644
--- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "sparc64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("SPARC Linux (kernel 4.4, glibc 2.23)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs
index 42944367cf6..69bb6e1fb60 100644
--- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "sparc64-unknown-netbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("NetBSD/sparc64".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs
index f0bf55d33e6..08f6eaf8361 100644
--- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "sparc64-unknown-openbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("OpenBSD/sparc64".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
index 5cee06e4936..8b7ff5d8011 100644
--- a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
@@ -5,10 +5,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "sparc-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("32-bit SPARC Linux".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
index cfe8f65d794..c977fe608a7 100644
--- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
@@ -21,10 +21,10 @@ pub fn target() -> Target {
         data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(),
         llvm_target: "sparc-unknown-none-elf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare 32-bit SPARC V7+".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "sparc".into(),
diff --git a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
index a42243f59dc..1c0adadece0 100644
--- a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "sparcv9-sun-solaris".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("SPARC Solaris 11, illumos".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64-S128".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs
index 9f222522505..96dd8588d4f 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv4t_none_eabi.rs
@@ -16,10 +16,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv4t-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Thumb-mode Bare ARMv4T".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "arm".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs
index 67e57c5fc35..d92e68cebaa 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv5te_none_eabi.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv5te-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Thumb-mode Bare ARMv5TE".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         arch: "arm".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs
index cac415128b6..a0fa58d8175 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv6m_none_eabi.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv6m-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARMv6-M".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs
index 13e1e349b04..e36aa5ab395 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7a_pc_windows_msvc.rs
@@ -15,9 +15,9 @@ pub fn target() -> Target {
         llvm_target: "thumbv7a-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs
index e3e2ea63594..2e68dd0ec4e 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7a_uwp_windows_msvc.rs
@@ -5,9 +5,9 @@ pub fn target() -> Target {
         llvm_target: "thumbv7a-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs
index ec73cf40a71..bd2df9236f6 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabi.rs
@@ -15,10 +15,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv7em-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARMv7E-M".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs
index bff812a5d5c..e2499ef5411 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs
@@ -14,10 +14,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv7em-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARMv7E-M, hardfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs
index 0104cdcc9a2..17e37f800f0 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7m_none_eabi.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv7m-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARMv7-M".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs
index d50e63b9217..c562f57252e 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_linux_androideabi.rs
@@ -14,10 +14,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-none-linux-android".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Thumb2-mode ARMv7-A Android with NEON".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs
index d630ca214e5..b5e91d61308 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_gnueabihf.rs
@@ -10,10 +10,12 @@ pub fn target() -> Target {
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some(
+                "Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23)".into(),
+            ),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs
index 74d5450c787..71d5eb43c10 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
         // doesn't support the "musleabihf" value.
         llvm_target: "armv7-unknown-linux-gnueabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Thumb2-mode ARMv7-A Linux with NEON, musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs
index 2f385208f36..e18bf113fe7 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_base_none_eabi.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.base-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARMv8-M Baseline".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs
index 29a0803ba07..5c2f1e09381 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabi.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.main-none-eabi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARMv8-M Mainline".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs
index 88796e7a756..799ac45b479 100644
--- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs
@@ -7,10 +7,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.main-none-eabihf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Bare ARMv8-M Mainline, hardfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
index 195ff46cf9d..46257a272d1 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
@@ -25,10 +25,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-unknown-emscripten".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("WebAssembly via Emscripten".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-S128-ni:1:10:20".into(),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
index 23f4772c39c..bf92f30e8b3 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
@@ -37,10 +37,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-unknown-unknown".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("WebAssembly".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
index 4c2d222b590..a8e7f22c068 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
@@ -51,10 +51,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-wasi".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("WebAssembly with WASI".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
index 38af48ab266..4e60806f3a7 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
@@ -63,9 +63,9 @@ pub fn target() -> Target {
         llvm_target: "wasm32-wasi".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
index 1259969ac36..63d1f4869be 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
@@ -62,10 +62,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-wasip2".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("WebAssembly".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
diff --git a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
index 8edde36dac6..bc49a3c9f70 100644
--- a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
@@ -40,10 +40,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm64-unknown-unknown".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("WebAssembly".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout: "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
index 21acd750df2..94638ae62f8 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
@@ -17,10 +17,10 @@ pub fn target() -> Target {
         // correctly, we do too.
         llvm_target: macos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit macOS (10.12+, Sierra+)".into()),
+            tier: Some(1),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
index ec61b796764..3cabca03360 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: ios_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit x86 iOS".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
index bd967ee972b..d3ba17cf027 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: mac_catalyst_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Apple Catalyst on x86_64".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
index 55b2e1afcd3..2a3125157dd 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
@@ -9,10 +9,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: tvos_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("x86 64-bit tvOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
index a783eff15b2..62e60b5e32d 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
@@ -6,10 +6,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: watchos_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("x86 64-bit Apple WatchOS simulator".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs
index 012450e307e..5a72fad8263 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_fortanix_unknown_sgx.rs
@@ -75,10 +75,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-elf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Fortanix ABI for 64-bit Intel SGX".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs
index 92711bbe246..257093b7554 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs
@@ -16,10 +16,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-linux-android".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit x86 Android".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
index c7169c3d62d..f6d22ff3204 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-pc-unknown".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("x86 64-bit QNX Neutrino 7.1 RTOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
index 4dbe049a4b7..697daf590ad 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-pc-solaris".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit Solaris 11, illumos".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
index de0f17246c3..89a9bb1e1cc 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
@@ -17,10 +17,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-pc-windows-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit MinGW (Windows 10+)".into()),
+            tier: Some(1),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
index b485970bb41..acf0fd421ba 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
@@ -12,10 +12,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-pc-windows-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit x86 MinGW (Windows 10+), LLVM ABI".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs
index 8752ba81066..883da26d786 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit Unikraft with musl 1.2.3".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         arch: "x86_64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs
index aef95e373cb..171a6f2a51e 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-dragonfly".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit DragonFlyBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs
index 15146a5ef72..4692b5a3c74 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs
@@ -14,10 +14,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-freebsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit FreeBSD".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs
index 80cdeab0a67..5ebf1804302 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs
@@ -12,10 +12,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-fuchsia".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit x86 Fuchsia".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs
index 9f62eb1fa27..b593b79e7bb 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-haiku".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit Haiku".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs
index 745a658ed00..3e81ff9a4ec 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs
@@ -4,10 +4,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-hermit".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("x86_64 Hermit".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         arch: "x86_64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs
index c52cdf466ab..d683a442027 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_illumos.rs
@@ -13,10 +13,10 @@ pub fn target() -> Target {
         // so we still pass Solaris to it
         llvm_target: "x86_64-pc-solaris".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("illumos".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs
index 6b170c22c9e..adf489ad7b1 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_l4re_uclibc.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
         llvm_target: "x86_64-unknown-l4re-uclibc".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
index bd12d4d8af0..4a92d4ef9d5 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
@@ -28,10 +28,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit Linux (kernel 3.2+, glibc 2.17+)".into()),
+            tier: Some(1),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs
index f6e0b051e8f..3c7db0095a1 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs
@@ -15,10 +15,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-linux-gnux32".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs
index 66237f07102..109fc3c0728 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs
@@ -18,10 +18,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit Linux with musl 1.2.3".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs
index db8db1d2538..c1d888899fc 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs
@@ -18,10 +18,10 @@ pub fn target() -> Target {
         // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
         llvm_target: "x86_64-unknown-linux-musl".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("x86_64 OpenHarmony".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs
index 38ae3a4fe42..d413caf4aaf 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs
@@ -19,10 +19,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-netbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("NetBSD/amd64".into()),
+            tier: Some(2),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs
index 5846dc16d66..549706998d4 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs
@@ -18,9 +18,7 @@ pub fn target() -> Target {
         relro_level: RelroLevel::Full,
         linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
         linker: Some("rust-lld".into()),
-        features:
-            "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
-                .into(),
+        features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float".into(),
         supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
         disable_redzone: true,
         panic_strategy: PanicStrategy::Abort,
@@ -30,10 +28,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-none-elf".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Freestanding/bare-metal x86_64 softfloat".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(false),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs
index 4d7eba24213..8f1c3ef9bc7 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs
@@ -12,10 +12,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-openbsd".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit OpenBSD".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs
index 99f5d9dc41d..ae38f63f034 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs
@@ -11,10 +11,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-redox".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("Redox OS".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
index 0c6e4b2b1ff..6da1fcca58c 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs
@@ -32,10 +32,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-unknown-windows".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit UEFI".into()),
+            tier: Some(2),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
index aef6fd1a781..c71bc9ed923 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
@@ -17,9 +17,9 @@ pub fn target() -> Target {
         llvm_target: "x86_64-pc-windows-gnu".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
index 963ccdbfcd0..178baeca685 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
         llvm_target: "x86_64-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
index 9b458614f2b..d44ae9fc4e0 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
     Target {
         llvm_target: "x86_64-win7-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("64-bit Windows 7 support".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs
index b956d228c17..7b40f7366d0 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs
@@ -13,9 +13,9 @@ pub fn target() -> Target {
         llvm_target: "x86_64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
index fe6cbca32c7..72cbc1be931 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
@@ -35,10 +35,10 @@ pub fn target() -> Target {
         // correctly, we do too.
         llvm_target: macos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
-            description: None,
-            tier: None,
-            host_tools: None,
-            std: None,
+            description: Some("macOS with late-gen Intel (at least Haswell)".into()),
+            tier: Some(3),
+            host_tools: Some(true),
+            std: Some(true),
         },
         pointer_width: 64,
         data_layout:
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 017fd3072fd..6667efb14e2 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -192,6 +192,11 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
     // 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)),
@@ -241,6 +246,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
     ("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),
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 f7ec5f1ff32..2e6247b4640 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
@@ -1776,6 +1776,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             true
         };
 
+        // we filter before checking if `impl_candidates` is empty
+        // to get the fallback solution if we filtered out any impls
+        let impl_candidates = impl_candidates
+            .into_iter()
+            .cloned()
+            .filter(|cand| {
+                !self.tcx.has_attrs_with_path(
+                    cand.impl_def_id,
+                    &[sym::diagnostic, sym::do_not_recommend],
+                )
+            })
+            .collect::<Vec<_>>();
+
         let def_id = trait_ref.def_id();
         if impl_candidates.is_empty() {
             if self.tcx.trait_is_auto(def_id)
@@ -1788,6 +1801,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             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| {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 2cf808f962f..f8843b892db 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3810,6 +3810,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             {
                 if let Some(where_pred) = where_pred.as_trait_clause()
                     && let Some(failed_pred) = failed_pred.as_trait_clause()
+                    && where_pred.def_id() == failed_pred.def_id()
                 {
                     self.enter_forall(where_pred, |where_pred| {
                         let failed_pred = self.instantiate_binder_with_fresh_vars(
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 703ff2f7f16..d28982ed849 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -271,13 +271,14 @@ fn do_normalize_predicates<'tcx>(
     // them here too, and we will remove this function when
     // we move over to lazy normalization *anyway*.
     let infcx = tcx.infer_ctxt().ignoring_regions().build();
-    let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
-        Ok(predicates) => predicates,
-        Err(errors) => {
-            let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
-            return Err(reported);
-        }
-    };
+    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
+    let predicates = ocx.normalize(&cause, elaborated_env, predicates);
+
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
+        return Err(reported);
+    }
 
     debug!("do_normalize_predicates: normalized predicates = {:?}", predicates);
 
@@ -465,37 +466,6 @@ pub fn normalize_param_env_or_error<'tcx>(
     ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal())
 }
 
-/// Normalize a type and process all resulting obligations, returning any errors.
-///
-/// FIXME(-Znext-solver): This should be replaced by `At::deeply_normalize`
-/// which has the same behavior with the new solver. Because using a separate
-/// fulfillment context worsens caching in the old solver, `At::deeply_normalize`
-/// is still lazy with the old solver as it otherwise negatively impacts perf.
-#[instrument(skip_all)]
-pub fn fully_normalize<'tcx, T>(
-    infcx: &InferCtxt<'tcx>,
-    cause: ObligationCause<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    value: T,
-) -> Result<T, Vec<FulfillmentError<'tcx>>>
-where
-    T: TypeFoldable<TyCtxt<'tcx>>,
-{
-    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
-    debug!(?value);
-    let normalized_value = ocx.normalize(&cause, param_env, value);
-    debug!(?normalized_value);
-    debug!("select_all_or_error start");
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
-        return Err(errors);
-    }
-    debug!("select_all_or_error complete");
-    let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
-    debug!(?resolved_value);
-    Ok(resolved_value)
-}
-
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
 /// hold. Used when creating vtables to check for unsatisfiable methods.
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 3a7481acbaf..01ba8c02ea6 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -42,11 +42,9 @@ impl<'tcx> At<'_, 'tcx> {
     /// same goals in both a temporary and the shared context which negatively impacts
     /// performance as these don't share caching.
     ///
-    /// FIXME(-Znext-solver): This has the same behavior as `traits::fully_normalize`
-    /// in the new solver, but because of performance reasons, we currently reuse an
-    /// existing fulfillment context in the old solver. Once we also eagerly prove goals with
-    /// the old solver or have removed the old solver, remove `traits::fully_normalize` and
-    /// rename this function to `At::fully_normalize`.
+    /// FIXME(-Znext-solver): For performance reasons, we currently reuse an existing
+    /// fulfillment context in the old solver. Once we have removed the old solver, we
+    /// can remove the `fulfill_cx` parameter on this function.
     fn deeply_normalize<T, E>(
         self,
         value: T,
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 6a904ef487e..3c33d13567d 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -18,9 +18,7 @@ use crate::error_reporting::traits::to_pretty_impl_header;
 use crate::errors::NegativePositiveConflict;
 use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{
-    self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt,
-};
+use crate::traits::{coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{codes::*, Diag, EmissionGuarantee};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -219,19 +217,17 @@ fn fulfill_implication<'tcx>(
         param_env, source_trait_ref, target_impl
     );
 
-    let source_trait_ref =
-        match traits::fully_normalize(infcx, ObligationCause::dummy(), param_env, source_trait_ref)
-        {
-            Ok(source_trait_ref) => source_trait_ref,
-            Err(_errors) => {
-                infcx.dcx().span_delayed_bug(
-                    infcx.tcx.def_span(source_impl),
-                    format!("failed to fully normalize {source_trait_ref}"),
-                );
-                source_trait_ref
-            }
-        };
+    let ocx = ObligationCtxt::new(infcx);
+    let source_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, source_trait_ref);
 
+    if !ocx.select_all_or_error().is_empty() {
+        infcx.dcx().span_delayed_bug(
+            infcx.tcx.def_span(source_impl),
+            format!("failed to fully normalize {source_trait_ref}"),
+        );
+    }
+
+    let source_trait_ref = infcx.resolve_vars_if_possible(source_trait_ref);
     let source_trait = ImplSubject::Trait(source_trait_ref);
 
     let selcx = SelectionContext::new(infcx);
@@ -253,9 +249,6 @@ fn fulfill_implication<'tcx>(
         return Err(());
     };
 
-    // Needs to be `in_snapshot` because this function is used to rebase
-    // generic parameters, which may happen inside of a select within a probe.
-    let ocx = ObligationCtxt::new(infcx);
     // attempt to prove all of the predicates for impl2 given those for impl1
     // (which are packed up in penv)
     ocx.register_obligations(obligations.chain(more_obligations));
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index f078cfe1b25..1dced9cf7cd 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -324,7 +324,7 @@ fn fn_sig_for_fn_abi<'tcx>(
 #[inline]
 fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv {
     use rustc_target::spec::abi::Abi::*;
-    match tcx.sess.target.adjust_abi(&tcx, abi, c_variadic) {
+    match tcx.sess.target.adjust_abi(abi, c_variadic) {
         RustIntrinsic | Rust | RustCall => Conv::Rust,
 
         // This is intentionally not using `Conv::Cold`, as that has to preserve
@@ -352,7 +352,6 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv {
         AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
         RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine },
         RiscvInterruptS => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor },
-        Wasm => Conv::C,
 
         // These API constants ought to be more specific...
         Cdecl { .. } => Conv::C,
@@ -744,6 +743,40 @@ fn fn_abi_adjust_for_abi<'tcx>(
                 return;
             }
 
+            // Avoid returning floats in x87 registers on x86 as loading and storing from x87
+            // registers will quiet signalling NaNs.
+            if cx.tcx.sess.target.arch == "x86"
+                && arg_idx.is_none()
+                // Intrinsics themselves are not actual "real" functions, so theres no need to
+                // change their ABIs.
+                && abi != SpecAbi::RustIntrinsic
+            {
+                match arg.layout.abi {
+                    // Handle similar to the way arguments with an `Abi::Aggregate` abi are handled
+                    // below, by returning arguments up to the size of a pointer (32 bits on x86)
+                    // cast to an appropriately sized integer.
+                    Abi::Scalar(s) if s.primitive() == Float(F32) => {
+                        // Same size as a pointer, return in a register.
+                        arg.cast_to(Reg::i32());
+                        return;
+                    }
+                    Abi::Scalar(s) if s.primitive() == Float(F64) => {
+                        // Larger than a pointer, return indirectly.
+                        arg.make_indirect();
+                        return;
+                    }
+                    Abi::ScalarPair(s1, s2)
+                        if matches!(s1.primitive(), Float(F32 | F64))
+                            || matches!(s2.primitive(), Float(F32 | F64)) =>
+                    {
+                        // Larger than a pointer, return indirectly.
+                        arg.make_indirect();
+                        return;
+                    }
+                    _ => {}
+                };
+            }
+
             match arg.layout.abi {
                 Abi::Aggregate { .. } => {}
 
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index de86a8536f7..f05d626b470 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -8,11 +8,10 @@ use std::hash::Hash;
 
 use rustc_ast_ir::Mutability;
 
-use crate::data_structures::HashSet;
 use crate::elaborate::Elaboratable;
 use crate::fold::{TypeFoldable, TypeSuperFoldable};
 use crate::relate::Relate;
-use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal};
+use crate::solve::Reveal;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
 
@@ -539,33 +538,6 @@ pub trait Features<I: Interner>: Copy {
     fn associated_const_equality(self) -> bool;
 }
 
-pub trait EvaluationCache<I: Interner> {
-    /// Insert a final result into the global cache.
-    fn insert(
-        &self,
-        tcx: I,
-        key: CanonicalInput<I>,
-        proof_tree: Option<I::CanonicalGoalEvaluationStepRef>,
-        additional_depth: usize,
-        encountered_overflow: bool,
-        cycle_participants: HashSet<CanonicalInput<I>>,
-        dep_node: I::DepNodeIndex,
-        result: QueryResult<I>,
-    );
-
-    /// Try to fetch a cached result, checking the recursion limit
-    /// and handling root goals of coinductive cycles.
-    ///
-    /// If this returns `Some` the cache result can be used.
-    fn get(
-        &self,
-        tcx: I,
-        key: CanonicalInput<I>,
-        stack_entries: impl IntoIterator<Item = CanonicalInput<I>>,
-        available_depth: usize,
-    ) -> Option<CacheData<I>>;
-}
-
 pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
     fn is_local(self) -> bool;
 
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index fdd1553d389..14ebbb12fe2 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -10,8 +10,11 @@ use crate::inherent::*;
 use crate::ir_print::IrPrint;
 use crate::lang_items::TraitSolverLangItem;
 use crate::relate::Relate;
+use crate::search_graph;
 use crate::solve::inspect::CanonicalGoalEvaluationStep;
-use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode};
+use crate::solve::{
+    CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
+};
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{self as ty};
 
@@ -86,6 +89,13 @@ pub trait Interner:
     ) -> Self::ExternalConstraints;
 
     type DepNodeIndex;
+    type Tracked<T: Debug + Clone>: Debug;
+    fn mk_tracked<T: Debug + Clone>(
+        self,
+        data: T,
+        dep_node: Self::DepNodeIndex,
+    ) -> Self::Tracked<T>;
+    fn get_tracked<T: Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T;
     fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex);
 
     // Kinds of tys
@@ -125,8 +135,11 @@ pub trait Interner:
     type Clause: Clause<Self>;
     type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
 
-    type EvaluationCache: EvaluationCache<Self>;
-    fn evaluation_cache(self, mode: SolverMode) -> Self::EvaluationCache;
+    fn with_global_cache<R>(
+        self,
+        mode: SolverMode,
+        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
+    ) -> R;
 
     fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
 
@@ -373,3 +386,32 @@ impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
         })
     }
 }
+
+impl<I: Interner> search_graph::Cx for I {
+    type ProofTree = Option<I::CanonicalGoalEvaluationStepRef>;
+    type Input = CanonicalInput<I>;
+    type Result = QueryResult<I>;
+
+    type DepNodeIndex = I::DepNodeIndex;
+    type Tracked<T: Debug + Clone> = I::Tracked<T>;
+    fn mk_tracked<T: Debug + Clone>(
+        self,
+        data: T,
+        dep_node_index: I::DepNodeIndex,
+    ) -> I::Tracked<T> {
+        I::mk_tracked(self, data, dep_node_index)
+    }
+    fn get_tracked<T: Debug + Clone>(self, tracked: &I::Tracked<T>) -> T {
+        I::get_tracked(self, tracked)
+    }
+    fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) {
+        I::with_cached_task(self, task)
+    }
+    fn with_global_cache<R>(
+        self,
+        mode: SolverMode,
+        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
+    ) -> R {
+        I::with_global_cache(self, mode, f)
+    }
+}
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index b14a65fc779..37ee66fa222 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -30,6 +30,7 @@ pub mod lang_items;
 pub mod lift;
 pub mod outlives;
 pub mod relate;
+pub mod search_graph;
 pub mod solve;
 
 // These modules are not `pub` since they are glob-imported.
diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs
new file mode 100644
index 00000000000..5ccda931f9c
--- /dev/null
+++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs
@@ -0,0 +1,118 @@
+use rustc_index::IndexVec;
+
+use super::{AvailableDepth, Cx, StackDepth, StackEntry};
+use crate::data_structures::{HashMap, HashSet};
+
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))]
+struct QueryData<X: Cx> {
+    result: X::Result,
+    proof_tree: X::ProofTree,
+}
+
+struct Success<X: Cx> {
+    data: X::Tracked<QueryData<X>>,
+    additional_depth: usize,
+}
+
+/// The cache entry for a given input.
+///
+/// This contains results whose computation never hit the
+/// recursion limit in `success`, and all results which hit
+/// the recursion limit in `with_overflow`.
+#[derive(derivative::Derivative)]
+#[derivative(Default(bound = ""))]
+struct CacheEntry<X: Cx> {
+    success: Option<Success<X>>,
+    /// We have to be careful when caching roots of cycles.
+    ///
+    /// See the doc comment of `StackEntry::cycle_participants` for more
+    /// details.
+    nested_goals: HashSet<X::Input>,
+    with_overflow: HashMap<usize, X::Tracked<QueryData<X>>>,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = ""))]
+pub(super) struct CacheData<'a, X: Cx> {
+    pub(super) result: X::Result,
+    pub(super) proof_tree: X::ProofTree,
+    pub(super) additional_depth: usize,
+    pub(super) encountered_overflow: bool,
+    // FIXME: This is currently unused, but impacts the design
+    // by requiring a closure for `Cx::with_global_cache`.
+    pub(super) nested_goals: &'a HashSet<X::Input>,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(Default(bound = ""))]
+pub struct GlobalCache<X: Cx> {
+    map: HashMap<X::Input, CacheEntry<X>>,
+}
+
+impl<X: Cx> GlobalCache<X> {
+    /// Insert a final result into the global cache.
+    pub(super) fn insert(
+        &mut self,
+        cx: X,
+        input: X::Input,
+
+        result: X::Result,
+        proof_tree: X::ProofTree,
+        dep_node: X::DepNodeIndex,
+
+        additional_depth: usize,
+        encountered_overflow: bool,
+        nested_goals: &HashSet<X::Input>,
+    ) {
+        let data = cx.mk_tracked(QueryData { result, proof_tree }, dep_node);
+        let entry = self.map.entry(input).or_default();
+        entry.nested_goals.extend(nested_goals);
+        if encountered_overflow {
+            entry.with_overflow.insert(additional_depth, data);
+        } else {
+            entry.success = Some(Success { data, additional_depth });
+        }
+    }
+
+    /// Try to fetch a cached result, checking the recursion limit
+    /// and handling root goals of coinductive cycles.
+    ///
+    /// If this returns `Some` the cache result can be used.
+    pub(super) fn get<'a>(
+        &'a self,
+        cx: X,
+        input: X::Input,
+        stack: &IndexVec<StackDepth, StackEntry<X>>,
+        available_depth: AvailableDepth,
+    ) -> Option<CacheData<'a, X>> {
+        let entry = self.map.get(&input)?;
+        if stack.iter().any(|e| entry.nested_goals.contains(&e.input)) {
+            return None;
+        }
+
+        if let Some(ref success) = entry.success {
+            if available_depth.cache_entry_is_applicable(success.additional_depth) {
+                let QueryData { result, proof_tree } = cx.get_tracked(&success.data);
+                return Some(CacheData {
+                    result,
+                    proof_tree,
+                    additional_depth: success.additional_depth,
+                    encountered_overflow: false,
+                    nested_goals: &entry.nested_goals,
+                });
+            }
+        }
+
+        entry.with_overflow.get(&available_depth.0).map(|e| {
+            let QueryData { result, proof_tree } = cx.get_tracked(e);
+            CacheData {
+                result,
+                proof_tree,
+                additional_depth: available_depth.0,
+                encountered_overflow: true,
+                nested_goals: &entry.nested_goals,
+            }
+        })
+    }
+}
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs
new file mode 100644
index 00000000000..c2204becdfd
--- /dev/null
+++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -0,0 +1,605 @@
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::marker::PhantomData;
+use std::mem;
+
+use rustc_index::{Idx, IndexVec};
+use tracing::debug;
+
+use crate::data_structures::{HashMap, HashSet};
+use crate::solve::SolverMode;
+
+mod global_cache;
+use global_cache::CacheData;
+pub use global_cache::GlobalCache;
+mod validate;
+
+/// The search graph does not simply use `Interner` directly
+/// to enable its fuzzing without having to stub the rest of
+/// the interner. We don't make this a super trait of `Interner`
+/// as users of the shared type library shouldn't have to care
+/// about `Input` and `Result` as they are implementation details
+/// of the search graph.
+pub trait Cx: Copy {
+    type ProofTree: Debug + Copy;
+    type Input: Debug + Eq + Hash + Copy;
+    type Result: Debug + Eq + Hash + Copy;
+
+    type DepNodeIndex;
+    type Tracked<T: Debug + Clone>: Debug;
+    fn mk_tracked<T: Debug + Clone>(
+        self,
+        data: T,
+        dep_node_index: Self::DepNodeIndex,
+    ) -> Self::Tracked<T>;
+    fn get_tracked<T: Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T;
+    fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex);
+
+    fn with_global_cache<R>(
+        self,
+        mode: SolverMode,
+        f: impl FnOnce(&mut GlobalCache<Self>) -> R,
+    ) -> R;
+}
+
+pub trait ProofTreeBuilder<X: Cx> {
+    fn try_apply_proof_tree(&mut self, proof_tree: X::ProofTree) -> bool;
+    fn on_provisional_cache_hit(&mut self);
+    fn on_cycle_in_stack(&mut self);
+    fn finalize_canonical_goal_evaluation(&mut self, cx: X) -> X::ProofTree;
+}
+
+pub trait Delegate {
+    type Cx: Cx;
+    const FIXPOINT_STEP_LIMIT: usize;
+    type ProofTreeBuilder: ProofTreeBuilder<Self::Cx>;
+
+    fn recursion_limit(cx: Self::Cx) -> usize;
+
+    fn initial_provisional_result(
+        cx: Self::Cx,
+        kind: CycleKind,
+        input: <Self::Cx as Cx>::Input,
+    ) -> <Self::Cx as Cx>::Result;
+    fn reached_fixpoint(
+        cx: Self::Cx,
+        kind: UsageKind,
+        input: <Self::Cx as Cx>::Input,
+        provisional_result: Option<<Self::Cx as Cx>::Result>,
+        result: <Self::Cx as Cx>::Result,
+    ) -> bool;
+    fn on_stack_overflow(
+        cx: Self::Cx,
+        inspect: &mut Self::ProofTreeBuilder,
+        input: <Self::Cx as Cx>::Input,
+    ) -> <Self::Cx as Cx>::Result;
+    fn on_fixpoint_overflow(
+        cx: Self::Cx,
+        input: <Self::Cx as Cx>::Input,
+    ) -> <Self::Cx as Cx>::Result;
+
+    fn step_is_coinductive(cx: Self::Cx, input: <Self::Cx as Cx>::Input) -> bool;
+}
+
+/// In the initial iteration of a cycle, we do not yet have a provisional
+/// result. In the case we return an initial provisional result depending
+/// on the kind of cycle.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum CycleKind {
+    Coinductive,
+    Inductive,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum UsageKind {
+    Single(CycleKind),
+    Mixed,
+}
+impl UsageKind {
+    fn merge(self, other: Self) -> Self {
+        match (self, other) {
+            (UsageKind::Single(lhs), UsageKind::Single(rhs)) => {
+                if lhs == rhs {
+                    UsageKind::Single(lhs)
+                } else {
+                    UsageKind::Mixed
+                }
+            }
+            (UsageKind::Mixed, UsageKind::Mixed)
+            | (UsageKind::Mixed, UsageKind::Single(_))
+            | (UsageKind::Single(_), UsageKind::Mixed) => UsageKind::Mixed,
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+struct AvailableDepth(usize);
+impl AvailableDepth {
+    /// Returns the remaining depth allowed for nested goals.
+    ///
+    /// This is generally simply one less than the current depth.
+    /// However, if we encountered overflow, we significantly reduce
+    /// the remaining depth of all nested goals to prevent hangs
+    /// in case there is exponential blowup.
+    fn allowed_depth_for_nested<D: Delegate>(
+        cx: D::Cx,
+        stack: &IndexVec<StackDepth, StackEntry<D::Cx>>,
+    ) -> Option<AvailableDepth> {
+        if let Some(last) = stack.raw.last() {
+            if last.available_depth.0 == 0 {
+                return None;
+            }
+
+            Some(if last.encountered_overflow {
+                AvailableDepth(last.available_depth.0 / 2)
+            } else {
+                AvailableDepth(last.available_depth.0 - 1)
+            })
+        } else {
+            Some(AvailableDepth(D::recursion_limit(cx)))
+        }
+    }
+
+    /// Whether we're allowed to use a global cache entry which required
+    /// the given depth.
+    fn cache_entry_is_applicable(self, additional_depth: usize) -> bool {
+        self.0 >= additional_depth
+    }
+}
+
+rustc_index::newtype_index! {
+    #[orderable]
+    #[gate_rustc_only]
+    pub struct StackDepth {}
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = ""))]
+struct StackEntry<X: Cx> {
+    input: X::Input,
+
+    available_depth: AvailableDepth,
+
+    /// The maximum depth reached by this stack entry, only up-to date
+    /// for the top of the stack and lazily updated for the rest.
+    reached_depth: StackDepth,
+
+    /// Whether this entry is a non-root cycle participant.
+    ///
+    /// We must not move the result of non-root cycle participants to the
+    /// global cache. We store the highest stack depth of a head of a cycle
+    /// this goal is involved in. This necessary to soundly cache its
+    /// provisional result.
+    non_root_cycle_participant: Option<StackDepth>,
+
+    encountered_overflow: bool,
+
+    has_been_used: Option<UsageKind>,
+
+    /// We put only the root goal of a coinductive cycle into the global cache.
+    ///
+    /// If we were to use that result when later trying to prove another cycle
+    /// participant, we can end up with unstable query results.
+    ///
+    /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
+    /// an example of where this is needed.
+    ///
+    /// There can  be multiple roots on the same stack, so we need to track
+    /// cycle participants per root:
+    /// ```plain
+    /// A :- B
+    /// B :- A, C
+    /// C :- D
+    /// D :- C
+    /// ```
+    nested_goals: HashSet<X::Input>,
+    /// Starts out as `None` and gets set when rerunning this
+    /// goal in case we encounter a cycle.
+    provisional_result: Option<X::Result>,
+}
+
+/// The provisional result for a goal which is not on the stack.
+#[derive(Debug)]
+struct DetachedEntry<X: Cx> {
+    /// The head of the smallest non-trivial cycle involving this entry.
+    ///
+    /// Given the following rules, when proving `A` the head for
+    /// the provisional entry of `C` would be `B`.
+    /// ```plain
+    /// A :- B
+    /// B :- C
+    /// C :- A + B + C
+    /// ```
+    head: StackDepth,
+    result: X::Result,
+}
+
+/// Stores the stack depth of a currently evaluated goal *and* already
+/// computed results for goals which depend on other goals still on the stack.
+///
+/// The provisional result may depend on whether the stack above it is inductive
+/// or coinductive. Because of this, we store separate provisional results for
+/// each case. If an provisional entry is not applicable, it may be the case
+/// that we already have provisional result while computing a goal. In this case
+/// we prefer the provisional result to potentially avoid fixpoint iterations.
+/// See tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs for an example.
+///
+/// The provisional cache can theoretically result in changes to the observable behavior,
+/// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs.
+#[derive(derivative::Derivative)]
+#[derivative(Default(bound = ""))]
+struct ProvisionalCacheEntry<X: Cx> {
+    stack_depth: Option<StackDepth>,
+    with_inductive_stack: Option<DetachedEntry<X>>,
+    with_coinductive_stack: Option<DetachedEntry<X>>,
+}
+
+impl<X: Cx> ProvisionalCacheEntry<X> {
+    fn is_empty(&self) -> bool {
+        self.stack_depth.is_none()
+            && self.with_inductive_stack.is_none()
+            && self.with_coinductive_stack.is_none()
+    }
+}
+
+pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
+    mode: SolverMode,
+    /// The stack of goals currently being computed.
+    ///
+    /// An element is *deeper* in the stack if its index is *lower*.
+    stack: IndexVec<StackDepth, StackEntry<X>>,
+    provisional_cache: HashMap<X::Input, ProvisionalCacheEntry<X>>,
+
+    _marker: PhantomData<D>,
+}
+
+impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
+    pub fn new(mode: SolverMode) -> SearchGraph<D> {
+        Self {
+            mode,
+            stack: Default::default(),
+            provisional_cache: Default::default(),
+            _marker: PhantomData,
+        }
+    }
+
+    pub fn solver_mode(&self) -> SolverMode {
+        self.mode
+    }
+
+    fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) {
+        if let Some(parent) = self.stack.raw.last_mut() {
+            parent.reached_depth = parent.reached_depth.max(reached_depth);
+            parent.encountered_overflow |= encountered_overflow;
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.stack.is_empty()
+    }
+
+    fn stack_coinductive_from(
+        cx: X,
+        stack: &IndexVec<StackDepth, StackEntry<X>>,
+        head: StackDepth,
+    ) -> bool {
+        stack.raw[head.index()..].iter().all(|entry| D::step_is_coinductive(cx, entry.input))
+    }
+
+    // When encountering a solver cycle, the result of the current goal
+    // depends on goals lower on the stack.
+    //
+    // We have to therefore be careful when caching goals. Only the final result
+    // of the cycle root, i.e. the lowest goal on the stack involved in this cycle,
+    // is moved to the global cache while all others are stored in a provisional cache.
+    //
+    // We update both the head of this cycle to rerun its evaluation until
+    // we reach a fixpoint and all other cycle participants to make sure that
+    // their result does not get moved to the global cache.
+    fn tag_cycle_participants(
+        stack: &mut IndexVec<StackDepth, StackEntry<X>>,
+        usage_kind: Option<UsageKind>,
+        head: StackDepth,
+    ) {
+        if let Some(usage_kind) = usage_kind {
+            stack[head].has_been_used =
+                Some(stack[head].has_been_used.map_or(usage_kind, |prev| prev.merge(usage_kind)));
+        }
+        debug_assert!(stack[head].has_been_used.is_some());
+
+        // The current root of these cycles. Note that this may not be the final
+        // root in case a later goal depends on a goal higher up the stack.
+        let mut current_root = head;
+        while let Some(parent) = stack[current_root].non_root_cycle_participant {
+            current_root = parent;
+            debug_assert!(stack[current_root].has_been_used.is_some());
+        }
+
+        let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1);
+        let current_cycle_root = &mut stack[current_root.as_usize()];
+        for entry in cycle_participants {
+            entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head));
+            current_cycle_root.nested_goals.insert(entry.input);
+            current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals));
+        }
+    }
+
+    fn clear_dependent_provisional_results(
+        provisional_cache: &mut HashMap<X::Input, ProvisionalCacheEntry<X>>,
+        head: StackDepth,
+    ) {
+        #[allow(rustc::potential_query_instability)]
+        provisional_cache.retain(|_, entry| {
+            if entry.with_coinductive_stack.as_ref().is_some_and(|p| p.head == head) {
+                entry.with_coinductive_stack.take();
+            }
+            if entry.with_inductive_stack.as_ref().is_some_and(|p| p.head == head) {
+                entry.with_inductive_stack.take();
+            }
+            !entry.is_empty()
+        });
+    }
+
+    /// Probably the most involved method of the whole solver.
+    ///
+    /// Given some goal which is proven via the `prove_goal` closure, this
+    /// handles caching, overflow, and coinductive cycles.
+    pub fn with_new_goal(
+        &mut self,
+        cx: X,
+        input: X::Input,
+        inspect: &mut D::ProofTreeBuilder,
+        mut prove_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result,
+    ) -> X::Result {
+        self.check_invariants();
+        // Check for overflow.
+        let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::<D>(cx, &self.stack)
+        else {
+            if let Some(last) = self.stack.raw.last_mut() {
+                last.encountered_overflow = true;
+            }
+
+            debug!("encountered stack overflow");
+            return D::on_stack_overflow(cx, inspect, input);
+        };
+
+        if let Some(result) = self.lookup_global_cache(cx, input, available_depth, inspect) {
+            return result;
+        }
+
+        // Check whether the goal is in the provisional cache.
+        // The provisional result may rely on the path to its cycle roots,
+        // so we have to check the path of the current goal matches that of
+        // the cache entry.
+        let cache_entry = self.provisional_cache.entry(input).or_default();
+        if let Some(entry) = cache_entry
+            .with_coinductive_stack
+            .as_ref()
+            .filter(|p| Self::stack_coinductive_from(cx, &self.stack, p.head))
+            .or_else(|| {
+                cache_entry
+                    .with_inductive_stack
+                    .as_ref()
+                    .filter(|p| !Self::stack_coinductive_from(cx, &self.stack, p.head))
+            })
+        {
+            debug!("provisional cache hit");
+            // We have a nested goal which is already in the provisional cache, use
+            // its result. We do not provide any usage kind as that should have been
+            // already set correctly while computing the cache entry.
+            inspect.on_provisional_cache_hit();
+            Self::tag_cycle_participants(&mut self.stack, None, entry.head);
+            return entry.result;
+        } else if let Some(stack_depth) = cache_entry.stack_depth {
+            debug!("encountered cycle with depth {stack_depth:?}");
+            // We have a nested goal which directly relies on a goal deeper in the stack.
+            //
+            // We start by tagging all cycle participants, as that's necessary for caching.
+            //
+            // Finally we can return either the provisional response or the initial response
+            // in case we're in the first fixpoint iteration for this goal.
+            inspect.on_cycle_in_stack();
+
+            let is_coinductive_cycle = Self::stack_coinductive_from(cx, &self.stack, stack_depth);
+            let cycle_kind =
+                if is_coinductive_cycle { CycleKind::Coinductive } else { CycleKind::Inductive };
+            Self::tag_cycle_participants(
+                &mut self.stack,
+                Some(UsageKind::Single(cycle_kind)),
+                stack_depth,
+            );
+
+            // Return the provisional result or, if we're in the first iteration,
+            // start with no constraints.
+            return if let Some(result) = self.stack[stack_depth].provisional_result {
+                result
+            } else {
+                D::initial_provisional_result(cx, cycle_kind, input)
+            };
+        } else {
+            // No entry, we push this goal on the stack and try to prove it.
+            let depth = self.stack.next_index();
+            let entry = StackEntry {
+                input,
+                available_depth,
+                reached_depth: depth,
+                non_root_cycle_participant: None,
+                encountered_overflow: false,
+                has_been_used: None,
+                nested_goals: Default::default(),
+                provisional_result: None,
+            };
+            assert_eq!(self.stack.push(entry), depth);
+            cache_entry.stack_depth = Some(depth);
+        };
+
+        // This is for global caching, so we properly track query dependencies.
+        // Everything that affects the `result` should be performed within this
+        // `with_anon_task` closure. If computing this goal depends on something
+        // not tracked by the cache key and from outside of this anon task, it
+        // must not be added to the global cache. Notably, this is the case for
+        // trait solver cycles participants.
+        let ((final_entry, result), dep_node) = cx.with_cached_task(|| {
+            for _ in 0..D::FIXPOINT_STEP_LIMIT {
+                match self.fixpoint_step_in_task(cx, input, inspect, &mut prove_goal) {
+                    StepResult::Done(final_entry, result) => return (final_entry, result),
+                    StepResult::HasChanged => debug!("fixpoint changed provisional results"),
+                }
+            }
+
+            debug!("canonical cycle overflow");
+            let current_entry = self.stack.pop().unwrap();
+            debug_assert!(current_entry.has_been_used.is_none());
+            let result = D::on_fixpoint_overflow(cx, input);
+            (current_entry, result)
+        });
+
+        let proof_tree = inspect.finalize_canonical_goal_evaluation(cx);
+
+        self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow);
+
+        // We're now done with this goal. In case this goal is involved in a larger cycle
+        // do not remove it from the provisional cache and update its provisional result.
+        // We only add the root of cycles to the global cache.
+        if let Some(head) = final_entry.non_root_cycle_participant {
+            let coinductive_stack = Self::stack_coinductive_from(cx, &self.stack, head);
+
+            let entry = self.provisional_cache.get_mut(&input).unwrap();
+            entry.stack_depth = None;
+            if coinductive_stack {
+                entry.with_coinductive_stack = Some(DetachedEntry { head, result });
+            } else {
+                entry.with_inductive_stack = Some(DetachedEntry { head, result });
+            }
+        } else {
+            // When encountering a cycle, both inductive and coinductive, we only
+            // move the root into the global cache. We also store all other cycle
+            // participants involved.
+            //
+            // We must not use the global cache entry of a root goal if a cycle
+            // participant is on the stack. This is necessary to prevent unstable
+            // results. See the comment of `StackEntry::nested_goals` for
+            // more details.
+            self.provisional_cache.remove(&input);
+            let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len();
+            cx.with_global_cache(self.mode, |cache| {
+                cache.insert(
+                    cx,
+                    input,
+                    result,
+                    proof_tree,
+                    dep_node,
+                    additional_depth,
+                    final_entry.encountered_overflow,
+                    &final_entry.nested_goals,
+                )
+            })
+        }
+
+        self.check_invariants();
+
+        result
+    }
+
+    /// Try to fetch a previously computed result from the global cache,
+    /// making sure to only do so if it would match the result of reevaluating
+    /// this goal.
+    fn lookup_global_cache(
+        &mut self,
+        cx: X,
+        input: X::Input,
+        available_depth: AvailableDepth,
+        inspect: &mut D::ProofTreeBuilder,
+    ) -> Option<X::Result> {
+        cx.with_global_cache(self.mode, |cache| {
+            let CacheData {
+                result,
+                proof_tree,
+                additional_depth,
+                encountered_overflow,
+                nested_goals: _, // FIXME: consider nested goals here.
+            } = cache.get(cx, input, &self.stack, available_depth)?;
+
+            // If we're building a proof tree and the current cache entry does not
+            // contain a proof tree, we do not use the entry but instead recompute
+            // the goal. We simply overwrite the existing entry once we're done,
+            // caching the proof tree.
+            if !inspect.try_apply_proof_tree(proof_tree) {
+                return None;
+            }
+
+            // Update the reached depth of the current goal to make sure
+            // its state is the same regardless of whether we've used the
+            // global cache or not.
+            let reached_depth = self.stack.next_index().plus(additional_depth);
+            self.update_parent_goal(reached_depth, encountered_overflow);
+
+            debug!("global cache hit");
+            Some(result)
+        })
+    }
+}
+
+enum StepResult<X: Cx> {
+    Done(StackEntry<X>, X::Result),
+    HasChanged,
+}
+
+impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
+    /// When we encounter a coinductive cycle, we have to fetch the
+    /// result of that cycle while we are still computing it. Because
+    /// of this we continuously recompute the cycle until the result
+    /// of the previous iteration is equal to the final result, at which
+    /// point we are done.
+    fn fixpoint_step_in_task<F>(
+        &mut self,
+        cx: X,
+        input: X::Input,
+        inspect: &mut D::ProofTreeBuilder,
+        prove_goal: &mut F,
+    ) -> StepResult<X>
+    where
+        F: FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result,
+    {
+        let result = prove_goal(self, inspect);
+        let stack_entry = self.stack.pop().unwrap();
+        debug_assert_eq!(stack_entry.input, input);
+
+        // If the current goal is not the root of a cycle, we are done.
+        let Some(usage_kind) = stack_entry.has_been_used else {
+            return StepResult::Done(stack_entry, result);
+        };
+
+        // If it is a cycle head, we have to keep trying to prove it until
+        // we reach a fixpoint. We need to do so for all cycle heads,
+        // not only for the root.
+        //
+        // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
+        // for an example.
+
+        // Start by clearing all provisional cache entries which depend on this
+        // the current goal.
+        Self::clear_dependent_provisional_results(
+            &mut self.provisional_cache,
+            self.stack.next_index(),
+        );
+
+        // Check whether we reached a fixpoint, either because the final result
+        // is equal to the provisional result of the previous iteration, or because
+        // this was only the root of either coinductive or inductive cycles, and the
+        // final result is equal to the initial response for that case.
+        //
+        // If we did not reach a fixpoint, update the provisional result and reevaluate.
+        if D::reached_fixpoint(cx, usage_kind, input, stack_entry.provisional_result, result) {
+            StepResult::Done(stack_entry, result)
+        } else {
+            let depth = self.stack.push(StackEntry {
+                has_been_used: None,
+                provisional_result: Some(result),
+                ..stack_entry
+            });
+            debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
+            StepResult::HasChanged
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/search_graph/validate.rs b/compiler/rustc_type_ir/src/search_graph/validate.rs
new file mode 100644
index 00000000000..1ae806834ba
--- /dev/null
+++ b/compiler/rustc_type_ir/src/search_graph/validate.rs
@@ -0,0 +1,75 @@
+use super::*;
+
+impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
+    #[allow(rustc::potential_query_instability)]
+    pub(super) fn check_invariants(&self) {
+        if !cfg!(debug_assertions) {
+            return;
+        }
+
+        let SearchGraph { mode: _, stack, provisional_cache, _marker } = self;
+        if stack.is_empty() {
+            assert!(provisional_cache.is_empty());
+        }
+
+        for (depth, entry) in stack.iter_enumerated() {
+            let StackEntry {
+                input,
+                available_depth: _,
+                reached_depth: _,
+                non_root_cycle_participant,
+                encountered_overflow: _,
+                has_been_used,
+                ref nested_goals,
+                provisional_result,
+            } = *entry;
+            let cache_entry = provisional_cache.get(&entry.input).unwrap();
+            assert_eq!(cache_entry.stack_depth, Some(depth));
+            if let Some(head) = non_root_cycle_participant {
+                assert!(head < depth);
+                assert!(nested_goals.is_empty());
+                assert_ne!(stack[head].has_been_used, None);
+
+                let mut current_root = head;
+                while let Some(parent) = stack[current_root].non_root_cycle_participant {
+                    current_root = parent;
+                }
+                assert!(stack[current_root].nested_goals.contains(&input));
+            }
+
+            if !nested_goals.is_empty() {
+                assert!(provisional_result.is_some() || has_been_used.is_some());
+                for entry in stack.iter().take(depth.as_usize()) {
+                    assert_eq!(nested_goals.get(&entry.input), None);
+                }
+            }
+        }
+
+        for (&input, entry) in &self.provisional_cache {
+            let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } =
+                entry;
+            assert!(
+                stack_depth.is_some()
+                    || with_coinductive_stack.is_some()
+                    || with_inductive_stack.is_some()
+            );
+
+            if let &Some(stack_depth) = stack_depth {
+                assert_eq!(stack[stack_depth].input, input);
+            }
+
+            let check_detached = |detached_entry: &DetachedEntry<X>| {
+                let DetachedEntry { head, result: _ } = *detached_entry;
+                assert_ne!(stack[head].has_been_used, None);
+            };
+
+            if let Some(with_coinductive_stack) = with_coinductive_stack {
+                check_detached(with_coinductive_stack);
+            }
+
+            if let Some(with_inductive_stack) = with_inductive_stack {
+                check_detached(with_inductive_stack);
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index 7934f996f0b..7934f996f0b 100644
--- a/compiler/rustc_type_ir/src/solve.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 01e4f1d1f33..9b912d16074 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1045,7 +1045,6 @@ pub enum Abi {
     AvrInterrupt,
     AvrNonBlockingInterrupt,
     CCmseNonSecureCall,
-    Wasm,
     System { unwind: bool },
     RustIntrinsic,
     RustCall,
diff --git a/config.example.toml b/config.example.toml
index 679abcdc777..a2c2fa1c2bd 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -1,6 +1,6 @@
 # Sample TOML configuration file for building Rust.
 #
-# To configure rustbuild, run `./configure` or `./x.py setup`.
+# To configure bootstrap, run `./configure` or `./x.py setup`.
 # See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-configtoml for more information.
 #
 # All options are commented out by default in this file, and they're commented
@@ -109,7 +109,7 @@
 # increases the size of binaries and consequently the memory required by
 # each linker process.
 # If set to 0, linker invocations are treated like any other job and
-# controlled by rustbuild's -j parameter.
+# controlled by bootstrap's -j parameter.
 #link-jobs = 0
 
 # Whether to build LLVM as a dynamically linked library (as opposed to statically linked).
@@ -371,11 +371,11 @@
 # Useful for modifying only the stage2 compiler without having to pass `--keep-stage 0` each time.
 #local-rebuild = false
 
-# Print out how long each rustbuild step took (mostly intended for CI and
+# Print out how long each bootstrap step took (mostly intended for CI and
 # tracking over time)
 #print-step-timings = false
 
-# Print out resource usage data for each rustbuild step, as defined by the Unix
+# Print out resource usage data for each bootstrap step, as defined by the Unix
 # struct rusage. (Note that this setting is completely unstable: the data it
 # captures, what platforms it supports, the format of its associated output, and
 # this setting's very existence, are all subject to change.)
@@ -609,7 +609,7 @@
 
 # Forces frame pointers to be used with `-Cforce-frame-pointers`.
 # This can be helpful for profiling at a small performance cost.
-# frame-pointers = false
+#frame-pointers = false
 
 # Indicates whether stack protectors should be used
 # via the unstable option `-Zstack-protector`.
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 65bcb241e4a..f299aa0124d 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1213,6 +1213,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// let static_ref: &'static mut usize = Box::leak(x);
     /// *static_ref += 1;
     /// assert_eq!(*static_ref, 42);
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Box::from_raw(static_ref) });
     /// ```
     ///
     /// Unsized data:
@@ -1222,6 +1225,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// let static_ref = Box::leak(x);
     /// static_ref[0] = 4;
     /// assert_eq!(*static_ref, [4, 2, 3]);
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Box::from_raw(static_ref) });
     /// ```
     #[stable(feature = "box_leak", since = "1.26.0")]
     #[inline]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 3745ecb48c1..9982c8ea6dc 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -665,16 +665,6 @@ impl<T> Rc<T> {
 }
 
 impl<T, A: Allocator> Rc<T, A> {
-    /// Returns a reference to the underlying allocator.
-    ///
-    /// Note: this is an associated function, which means that you have
-    /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This
-    /// is so that there is no conflict with a method on the inner type.
-    #[inline]
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    pub fn allocator(this: &Self) -> &A {
-        &this.alloc
-    }
     /// Constructs a new `Rc` in the provided allocator.
     ///
     /// # Examples
@@ -1287,6 +1277,8 @@ impl<T: ?Sized> Rc<T> {
     ///
     ///     let five = Rc::from_raw(ptr);
     ///     assert_eq!(2, Rc::strong_count(&five));
+    /// #   // Prevent leaks for Miri.
+    /// #   Rc::decrement_strong_count(ptr);
     /// }
     /// ```
     #[inline]
@@ -1331,6 +1323,17 @@ impl<T: ?Sized> Rc<T> {
 }
 
 impl<T: ?Sized, A: Allocator> Rc<T, A> {
+    /// Returns a reference to the underlying allocator.
+    ///
+    /// Note: this is an associated function, which means that you have
+    /// to call it as `Rc::allocator(&r)` instead of `r.allocator()`. This
+    /// is so that there is no conflict with a method on the inner type.
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn allocator(this: &Self) -> &A {
+        &this.alloc
+    }
+
     /// Consumes the `Rc`, returning the wrapped pointer.
     ///
     /// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -1344,6 +1347,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// let x = Rc::new("hello".to_owned());
     /// let x_ptr = Rc::into_raw(x);
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
+    /// # // Prevent leaks for Miri.
+    /// # drop(unsafe { Rc::from_raw(x_ptr) });
     /// ```
     #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "rc_raw", since = "1.17.0")]
@@ -1571,6 +1576,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     ///
     ///     let five = Rc::from_raw_in(ptr, System);
     ///     assert_eq!(2, Rc::strong_count(&five));
+    /// #   // Prevent leaks for Miri.
+    /// #   Rc::decrement_strong_count_in(ptr, System);
     /// }
     /// ```
     #[inline]
@@ -2994,6 +3001,13 @@ impl<T: ?Sized> Weak<T> {
 }
 
 impl<T: ?Sized, A: Allocator> Weak<T, A> {
+    /// Returns a reference to the underlying allocator.
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn allocator(&self) -> &A {
+        &self.alloc
+    }
+
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
     /// The pointer is valid only if there are some strong references. The pointer may be dangling,
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 36078da7c35..07ffd3e1519 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1984,6 +1984,9 @@ impl String {
     /// let x = String::from("bucket");
     /// let static_ref: &'static mut str = x.leak();
     /// assert_eq!(static_ref, "bucket");
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Box::from_raw(static_ref) });
     /// ```
     #[stable(feature = "string_leak", since = "1.72.0")]
     #[inline]
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 1983ea8281a..a905a1e6b7e 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -677,16 +677,6 @@ impl<T> Arc<T> {
 }
 
 impl<T, A: Allocator> Arc<T, A> {
-    /// Returns a reference to the underlying allocator.
-    ///
-    /// Note: this is an associated function, which means that you have
-    /// to call it as `Arc::allocator(&a)` instead of `a.allocator()`. This
-    /// is so that there is no conflict with a method on the inner type.
-    #[inline]
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    pub fn allocator(this: &Self) -> &A {
-        &this.alloc
-    }
     /// Constructs a new `Arc<T>` in the provided allocator.
     ///
     /// # Examples
@@ -1424,6 +1414,8 @@ impl<T: ?Sized> Arc<T> {
     ///     // the `Arc` between threads.
     ///     let five = Arc::from_raw(ptr);
     ///     assert_eq!(2, Arc::strong_count(&five));
+    /// #   // Prevent leaks for Miri.
+    /// #   Arc::decrement_strong_count(ptr);
     /// }
     /// ```
     #[inline]
@@ -1470,6 +1462,17 @@ impl<T: ?Sized> Arc<T> {
 }
 
 impl<T: ?Sized, A: Allocator> Arc<T, A> {
+    /// Returns a reference to the underlying allocator.
+    ///
+    /// Note: this is an associated function, which means that you have
+    /// to call it as `Arc::allocator(&a)` instead of `a.allocator()`. This
+    /// is so that there is no conflict with a method on the inner type.
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn allocator(this: &Self) -> &A {
+        &this.alloc
+    }
+
     /// Consumes the `Arc`, returning the wrapped pointer.
     ///
     /// To avoid a memory leak the pointer must be converted back to an `Arc` using
@@ -1483,6 +1486,8 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// let x = Arc::new("hello".to_owned());
     /// let x_ptr = Arc::into_raw(x);
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
+    /// # // Prevent leaks for Miri.
+    /// # drop(unsafe { Arc::from_raw(x_ptr) });
     /// ```
     #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "rc_raw", since = "1.17.0")]
@@ -1765,6 +1770,8 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     ///     // the `Arc` between threads.
     ///     let five = Arc::from_raw_in(ptr, System);
     ///     assert_eq!(2, Arc::strong_count(&five));
+    /// #   // Prevent leaks for Miri.
+    /// #   Arc::decrement_strong_count_in(ptr, System);
     /// }
     /// ```
     #[inline]
@@ -2715,6 +2722,13 @@ impl<T: ?Sized> Weak<T> {
 }
 
 impl<T: ?Sized, A: Allocator> Weak<T, A> {
+    /// Returns a reference to the underlying allocator.
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn allocator(&self) -> &A {
+        &self.alloc
+    }
+
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
     /// The pointer is valid only if there are some strong references. The pointer may be dangling,
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 3bd89eaa6cb..10f62e4bb62 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -120,10 +120,15 @@ impl<T, A: Allocator> IntoIter<T, A> {
     /// This is roughly equivalent to the following, but more efficient
     ///
     /// ```
-    /// # let mut into_iter = Vec::<u8>::with_capacity(10).into_iter();
+    /// # let mut vec = Vec::<u8>::with_capacity(10);
+    /// # let ptr = vec.as_mut_ptr();
+    /// # let mut into_iter = vec.into_iter();
     /// let mut into_iter = std::mem::replace(&mut into_iter, Vec::new().into_iter());
     /// (&mut into_iter).for_each(drop);
     /// std::mem::forget(into_iter);
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Vec::<u8>::from_raw_parts(ptr, 0, 10) });
     /// ```
     ///
     /// This method is used by in-place iteration, refer to the vec::in_place_collect
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 6e9b017ad75..729d5dd4fe4 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1473,6 +1473,9 @@ impl<T, A: Allocator> Vec<T, A> {
     /// // 2. `0 <= capacity` always holds whatever `capacity` is.
     /// unsafe {
     ///     vec.set_len(0);
+    /// #   // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// #   // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// #   vec.set_len(3);
     /// }
     /// ```
     ///
@@ -2391,6 +2394,9 @@ impl<T, A: Allocator> Vec<T, A> {
     /// let static_ref: &'static mut [usize] = x.leak();
     /// static_ref[0] += 1;
     /// assert_eq!(static_ref, &[2, 2, 3]);
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # drop(unsafe { Box::from_raw(static_ref) });
     /// ```
     #[stable(feature = "vec_leak", since = "1.47.0")]
     #[inline]
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index bc026d0a446..ccb1cc4e974 100644
--- a/library/core/src/borrow.rs
+++ b/library/core/src/borrow.rs
@@ -184,6 +184,7 @@ pub trait Borrow<Borrowed: ?Sized> {
 /// an underlying type by providing a mutable reference. See [`Borrow<T>`]
 /// for more information on borrowing as another type.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "BorrowMut"]
 pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
     /// Mutably borrows from an owned value.
     ///
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index 7c7130ec075..21452d40f9d 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -67,7 +67,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(lazy_cell_consume)]
+    /// #![feature(lazy_cell_into_inner)]
     ///
     /// use std::cell::LazyCell;
     ///
@@ -78,7 +78,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
     /// assert_eq!(&*lazy, "HELLO, WORLD!");
     /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
     /// ```
-    #[unstable(feature = "lazy_cell_consume", issue = "125623")]
+    #[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
     pub fn into_inner(this: Self) -> Result<T, F> {
         match this.state.into_inner() {
             State::Init(data) => Ok(data),
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 458be49fb15..4186565c131 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -223,7 +223,10 @@ impl char {
     /// assert_eq!('❤', c);
     /// ```
     #[stable(feature = "assoc_char_funcs", since = "1.52.0")]
-    #[rustc_const_unstable(feature = "const_char_from_u32_unchecked", issue = "89259")]
+    #[rustc_const_stable(
+        feature = "const_char_from_u32_unchecked",
+        since = "CURRENT_RUSTC_VERSION"
+    )]
     #[must_use]
     #[inline]
     pub const unsafe fn from_u32_unchecked(i: u32) -> char {
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index f3683fe3f9c..26b463e25ea 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -123,7 +123,7 @@ pub const fn from_u32(i: u32) -> Option<char> {
 /// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`].
 /// instead.
 #[stable(feature = "char_from_unchecked", since = "1.5.0")]
-#[rustc_const_unstable(feature = "const_char_from_u32_unchecked", issue = "89259")]
+#[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "CURRENT_RUSTC_VERSION")]
 #[must_use]
 #[inline]
 pub const unsafe fn from_u32_unchecked(i: u32) -> char {
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index d2a408485d1..76752f22ed8 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -263,8 +263,6 @@ impl CStr {
     /// ```
     ///
     /// ```
-    /// #![feature(const_cstr_from_ptr)]
-    ///
     /// use std::ffi::{c_char, CStr};
     ///
     /// const HELLO_PTR: *const c_char = {
@@ -280,11 +278,11 @@ impl CStr {
     #[inline] // inline is necessary for codegen to see strlen.
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
+    #[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
         // SAFETY: The caller has provided a pointer that points to a valid C
         // string with a NUL terminator less than `isize::MAX` from `ptr`.
-        let len = unsafe { const_strlen(ptr) };
+        let len = unsafe { strlen(ptr) };
 
         // SAFETY: The caller has provided a valid pointer with length less than
         // `isize::MAX`, so `from_raw_parts` is safe. The content remains valid
@@ -542,7 +540,7 @@ impl CStr {
     #[must_use]
     #[doc(alias("len", "strlen"))]
     #[stable(feature = "cstr_count_bytes", since = "1.79.0")]
-    #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
+    #[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")]
     pub const fn count_bytes(&self) -> usize {
         self.inner.len() - 1
     }
@@ -742,7 +740,10 @@ impl AsRef<CStr> for CStr {
 /// The pointer must point to a valid buffer that contains a NUL terminator. The NUL must be
 /// located within `isize::MAX` from `ptr`.
 #[inline]
-const unsafe fn const_strlen(ptr: *const c_char) -> usize {
+#[unstable(feature = "cstr_internals", issue = "none")]
+#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+const unsafe fn strlen(ptr: *const c_char) -> usize {
     const fn strlen_ct(s: *const c_char) -> usize {
         let mut len = 0;
 
diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs
index 0168b11c739..243f938bce2 100644
--- a/library/core/src/iter/sources/repeat.rs
+++ b/library/core/src/iter/sources/repeat.rs
@@ -8,11 +8,15 @@ use crate::num::NonZero;
 /// Infinite iterators like `repeat()` are often used with adapters like
 /// [`Iterator::take()`], in order to make them finite.
 ///
+/// Use [`str::repeat()`] instead of this function if you just want to repeat
+/// a char/string `n`th times.
+///
 /// If the element type of the iterator you need does not implement `Clone`,
 /// or if you do not want to keep the repeated element in memory, you can
 /// instead use the [`repeat_with()`] function.
 ///
 /// [`repeat_with()`]: crate::iter::repeat_with
+/// [`str::repeat()`]: ../../std/primitive.str.html#method.repeat
 ///
 /// # Examples
 ///
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 0f82f01e57a..49f89e70255 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -119,7 +119,6 @@
 #![feature(const_bigint_helper_methods)]
 #![feature(const_black_box)]
 #![feature(const_cell_into_inner)]
-#![feature(const_char_from_u32_unchecked)]
 #![feature(const_eval_select)]
 #![feature(const_exact_div)]
 #![feature(const_float_bits_conv)]
diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs
index e0c3b9f3b51..997f088c6d6 100644
--- a/library/core/src/mem/manually_drop.rs
+++ b/library/core/src/mem/manually_drop.rs
@@ -62,6 +62,9 @@ impl<T> ManuallyDrop<T> {
     /// x.truncate(5); // You can still safely operate on the value
     /// assert_eq!(*x, "Hello");
     /// // But `Drop` will not be run here
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # let _ = ManuallyDrop::into_inner(x);
     /// ```
     #[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"]
     #[stable(feature = "manually_drop", since = "1.20.0")]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 24ebe33bb2c..dd40f57dc87 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -274,6 +274,8 @@ impl<T> MaybeUninit<T> {
     /// use std::mem::MaybeUninit;
     ///
     /// let v: MaybeUninit<Vec<u8>> = MaybeUninit::new(vec![42]);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { let _ = MaybeUninit::assume_init(v); }
     /// ```
     ///
     /// [`assume_init`]: MaybeUninit::assume_init
@@ -446,6 +448,9 @@ impl<T> MaybeUninit<T> {
     /// let mut x = MaybeUninit::<String>::uninit();
     ///
     /// x.write("Hello".to_string());
+    /// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
+    /// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
+    /// # unsafe { MaybeUninit::assume_init_drop(&mut x); }
     /// // This leaks the contained string:
     /// x.write("hello".to_string());
     /// // x is initialized now:
@@ -506,6 +511,8 @@ impl<T> MaybeUninit<T> {
     /// // Create a reference into the `MaybeUninit<T>`. This is okay because we initialized it.
     /// let x_vec = unsafe { &*x.as_ptr() };
     /// assert_eq!(x_vec.len(), 3);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { MaybeUninit::assume_init_drop(&mut x); }
     /// ```
     ///
     /// *Incorrect* usage of this method:
@@ -545,6 +552,8 @@ impl<T> MaybeUninit<T> {
     /// let x_vec = unsafe { &mut *x.as_mut_ptr() };
     /// x_vec.push(3);
     /// assert_eq!(x_vec.len(), 4);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { MaybeUninit::assume_init_drop(&mut x); }
     /// ```
     ///
     /// *Incorrect* usage of this method:
@@ -746,6 +755,8 @@ impl<T> MaybeUninit<T> {
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
+    /// # let mut x_mu = x;
+    /// # let mut x = &mut x_mu;
     /// // Initialize `x`:
     /// x.write(vec![1, 2, 3]);
     /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to
@@ -755,6 +766,8 @@ impl<T> MaybeUninit<T> {
     ///     x.assume_init_ref()
     /// };
     /// assert_eq!(x, &vec![1, 2, 3]);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { MaybeUninit::assume_init_drop(&mut x_mu); }
     /// ```
     ///
     /// ### *Incorrect* usages of this method:
@@ -1088,6 +1101,8 @@ impl<T> MaybeUninit<T> {
     /// let init = MaybeUninit::clone_from_slice(&mut dst, &src);
     ///
     /// assert_eq!(init, src);
+    /// # // Prevent leaks for Miri
+    /// # unsafe { std::ptr::drop_in_place(init); }
     /// ```
     ///
     /// ```
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 58ed98c888c..05dc1e97852 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -12,7 +12,10 @@
 #![unstable(feature = "f128", issue = "116909")]
 
 use crate::convert::FloatToInt;
+#[cfg(not(test))]
+use crate::intrinsics;
 use crate::mem;
+use crate::num::FpCategory;
 
 /// Basic mathematical constants.
 #[unstable(feature = "f128", issue = "116909")]
@@ -167,7 +170,7 @@ impl f128 {
     /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
     /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
     #[unstable(feature = "f128", issue = "116909")]
-    pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128;
+    pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128;
 
     /// Smallest finite `f128` value.
     ///
@@ -175,7 +178,7 @@ impl f128 {
     ///
     /// [`MAX`]: f128::MAX
     #[unstable(feature = "f128", issue = "116909")]
-    pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128;
+    pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128;
     /// Smallest positive normal `f128` value.
     ///
     /// Equal to 2<sup>[`MIN_EXP`]&nbsp;&minus;&nbsp;1</sup>.
@@ -191,7 +194,7 @@ impl f128 {
     /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
     /// [`MAX_EXP`]: f128::MAX_EXP
     #[unstable(feature = "f128", issue = "116909")]
-    pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128;
+    pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128;
 
     /// One greater than the minimum possible normal power of 2 exponent.
     ///
@@ -251,6 +254,12 @@ impl f128 {
     #[cfg(not(bootstrap))]
     pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
 
+    /// Exponent mask
+    pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;
+
+    /// Mantissa mask
+    pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
+
     /// Minimum representable positive value (min subnormal)
     #[cfg(not(bootstrap))]
     const TINY_BITS: u128 = 0x1;
@@ -354,6 +363,119 @@ impl f128 {
         self.abs_private() < Self::INFINITY
     }
 
+    /// Returns `true` if the number is [subnormal].
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # // FIXME(f16_f128): remove when `eqtf2` is available
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
+    ///
+    /// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128
+    /// let max = f128::MAX;
+    /// let lower_than_min = 1.0e-4960_f128;
+    /// let zero = 0.0_f128;
+    ///
+    /// assert!(!min.is_subnormal());
+    /// assert!(!max.is_subnormal());
+    ///
+    /// assert!(!zero.is_subnormal());
+    /// assert!(!f128::NAN.is_subnormal());
+    /// assert!(!f128::INFINITY.is_subnormal());
+    /// // Values between `0` and `min` are Subnormal.
+    /// assert!(lower_than_min.is_subnormal());
+    /// # }
+    /// ```
+    ///
+    /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+    #[inline]
+    #[must_use]
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    pub const fn is_subnormal(self) -> bool {
+        matches!(self.classify(), FpCategory::Subnormal)
+    }
+
+    /// Returns `true` if the number is neither zero, infinite, [subnormal], or NaN.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # // FIXME(f16_f128): remove when `eqtf2` is available
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
+    ///
+    /// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128
+    /// let max = f128::MAX;
+    /// let lower_than_min = 1.0e-4960_f128;
+    /// let zero = 0.0_f128;
+    ///
+    /// assert!(min.is_normal());
+    /// assert!(max.is_normal());
+    ///
+    /// assert!(!zero.is_normal());
+    /// assert!(!f128::NAN.is_normal());
+    /// assert!(!f128::INFINITY.is_normal());
+    /// // Values between `0` and `min` are Subnormal.
+    /// assert!(!lower_than_min.is_normal());
+    /// # }
+    /// ```
+    ///
+    /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+    #[inline]
+    #[must_use]
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    pub const fn is_normal(self) -> bool {
+        matches!(self.classify(), FpCategory::Normal)
+    }
+
+    /// Returns the floating point category of the number. If only one property
+    /// is going to be tested, it is generally faster to use the specific
+    /// predicate instead.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    /// # // FIXME(f16_f128): remove when `eqtf2` is available
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
+    ///
+    /// use std::num::FpCategory;
+    ///
+    /// let num = 12.4_f128;
+    /// let inf = f128::INFINITY;
+    ///
+    /// assert_eq!(num.classify(), FpCategory::Normal);
+    /// assert_eq!(inf.classify(), FpCategory::Infinite);
+    /// # }
+    /// ```
+    #[inline]
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    pub const fn classify(self) -> FpCategory {
+        // Other float types cannot use a bitwise classify because they may suffer a variety
+        // of errors if the backend chooses to cast to different float types (x87). `f128` cannot
+        // fit into any other float types so this is not a concern, and we rely on bit patterns.
+
+        // SAFETY: POD bitcast, same as in `to_bits`.
+        let bits = unsafe { mem::transmute::<f128, u128>(self) };
+        Self::classify_bits(bits)
+    }
+
+    /// This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
+    /// FIXME(jubilee): In a just world, this would be the entire impl for classify,
+    /// plus a transmute. We do not live in a just world, but we can make it more so.
+    #[inline]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    const fn classify_bits(b: u128) -> FpCategory {
+        match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
+            (0, Self::EXP_MASK) => FpCategory::Infinite,
+            (_, Self::EXP_MASK) => FpCategory::Nan,
+            (0, 0) => FpCategory::Zero,
+            (_, 0) => FpCategory::Subnormal,
+            _ => FpCategory::Normal,
+        }
+    }
+
     /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
     /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
     /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
@@ -638,12 +760,52 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
-    pub fn to_bits(self) -> u128 {
-        // SAFETY: `u128` is a plain old datatype so we can always... uh...
-        // ...look, just pretend you forgot what you just read.
-        // Stability concerns.
-        unsafe { mem::transmute(self) }
+    pub const fn to_bits(self) -> u128 {
+        // SAFETY: `u128` is a plain old datatype so we can always transmute to it.
+        // ...sorta.
+        //
+        // It turns out that at runtime, it is possible for a floating point number
+        // to be subject to a floating point mode that alters nonzero subnormal numbers
+        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+        //
+        // And, of course evaluating to a NaN value is fairly nondeterministic.
+        // More precisely: when NaN should be returned is knowable, but which NaN?
+        // So far that's defined by a combination of LLVM and the CPU, not Rust.
+        // This function, however, allows observing the bitstring of a NaN,
+        // thus introspection on CTFE.
+        //
+        // In order to preserve, at least for the moment, const-to-runtime equivalence,
+        // we reject any of these possible situations from happening.
+        #[inline]
+        #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+        const fn ct_f128_to_u128(ct: f128) -> u128 {
+            // FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but that
+            // is not available on all platforms (needs `netf2` and `unordtf2`). So classify
+            // the bits instead.
+
+            // SAFETY: this is a POD transmutation
+            let bits = unsafe { mem::transmute::<f128, u128>(ct) };
+            match f128::classify_bits(bits) {
+                FpCategory::Nan => {
+                    panic!("const-eval error: cannot use f128::to_bits on a NaN")
+                }
+                FpCategory::Subnormal => {
+                    panic!("const-eval error: cannot use f128::to_bits on a subnormal number")
+                }
+                FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits,
+            }
+        }
+
+        #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+        fn rt_f128_to_u128(x: f128) -> u128 {
+            // SAFETY: `u128` is a plain old datatype so we can always... uh...
+            // ...look, just pretend you forgot what you just read.
+            // Stability concerns.
+            unsafe { mem::transmute(x) }
+        }
+        intrinsics::const_eval_select((self,), ct_f128_to_u128, rt_f128_to_u128)
     }
 
     /// Raw transmutation from `u128`.
@@ -688,11 +850,52 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    pub fn from_bits(v: u128) -> Self {
-        // SAFETY: `u128 is a plain old datatype so we can always... uh...
-        // ...look, just pretend you forgot what you just read.
-        // Stability concerns.
-        unsafe { mem::transmute(v) }
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+    pub const fn from_bits(v: u128) -> Self {
+        // It turns out the safety issues with sNaN were overblown! Hooray!
+        // SAFETY: `u128` is a plain old datatype so we can always transmute from it
+        // ...sorta.
+        //
+        // It turns out that at runtime, it is possible for a floating point number
+        // to be subject to floating point modes that alter nonzero subnormal numbers
+        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+        // This is not a problem usually, but at least one tier2 platform for Rust
+        // actually exhibits this behavior by default: thumbv7neon
+        // aka "the Neon FPU in AArch32 state"
+        //
+        // And, of course evaluating to a NaN value is fairly nondeterministic.
+        // More precisely: when NaN should be returned is knowable, but which NaN?
+        // So far that's defined by a combination of LLVM and the CPU, not Rust.
+        // This function, however, allows observing the bitstring of a NaN,
+        // thus introspection on CTFE.
+        //
+        // In order to preserve, at least for the moment, const-to-runtime equivalence,
+        // reject any of these possible situations from happening.
+        #[inline]
+        #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+        const fn ct_u128_to_f128(ct: u128) -> f128 {
+            match f128::classify_bits(ct) {
+                FpCategory::Subnormal => {
+                    panic!("const-eval error: cannot use f128::from_bits on a subnormal number")
+                }
+                FpCategory::Nan => {
+                    panic!("const-eval error: cannot use f128::from_bits on NaN")
+                }
+                FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+                    // SAFETY: It's not a frumious number
+                    unsafe { mem::transmute::<u128, f128>(ct) }
+                }
+            }
+        }
+
+        #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+        fn rt_u128_to_f128(x: u128) -> f128 {
+            // SAFETY: `u128` is a plain old datatype so we can always... uh...
+            // ...look, just pretend you forgot what you just read.
+            // Stability concerns.
+            unsafe { mem::transmute(x) }
+        }
+        intrinsics::const_eval_select((v,), ct_u128_to_f128, rt_u128_to_f128)
     }
 
     /// Return the memory representation of this floating point number as a byte array in
@@ -715,8 +918,9 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
-    pub fn to_be_bytes(self) -> [u8; 16] {
+    pub const fn to_be_bytes(self) -> [u8; 16] {
         self.to_bits().to_be_bytes()
     }
 
@@ -740,8 +944,9 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
-    pub fn to_le_bytes(self) -> [u8; 16] {
+    pub const fn to_le_bytes(self) -> [u8; 16] {
         self.to_bits().to_le_bytes()
     }
 
@@ -776,8 +981,9 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
-    pub fn to_ne_bytes(self) -> [u8; 16] {
+    pub const fn to_ne_bytes(self) -> [u8; 16] {
         self.to_bits().to_ne_bytes()
     }
 
@@ -803,7 +1009,8 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    pub fn from_be_bytes(bytes: [u8; 16]) -> Self {
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+    pub const fn from_be_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_be_bytes(bytes))
     }
 
@@ -829,7 +1036,8 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    pub fn from_le_bytes(bytes: [u8; 16]) -> Self {
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+    pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_le_bytes(bytes))
     }
 
@@ -865,7 +1073,8 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    pub fn from_ne_bytes(bytes: [u8; 16]) -> Self {
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+    pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_ne_bytes(bytes))
     }
 
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index e74300d6c2f..2a8ede93838 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -12,7 +12,10 @@
 #![unstable(feature = "f16", issue = "116909")]
 
 use crate::convert::FloatToInt;
+#[cfg(not(test))]
+use crate::intrinsics;
 use crate::mem;
+use crate::num::FpCategory;
 
 /// Basic mathematical constants.
 #[unstable(feature = "f16", issue = "116909")]
@@ -244,7 +247,13 @@ impl f16 {
 
     /// Sign bit
     #[cfg(not(bootstrap))]
-    const SIGN_MASK: u16 = 0x8000;
+    pub(crate) const SIGN_MASK: u16 = 0x8000;
+
+    /// Exponent mask
+    pub(crate) const EXP_MASK: u16 = 0x7c00;
+
+    /// Mantissa mask
+    pub(crate) const MAN_MASK: u16 = 0x03ff;
 
     /// Minimum representable positive value (min subnormal)
     #[cfg(not(bootstrap))]
@@ -344,6 +353,159 @@ impl f16 {
         self.abs_private() < Self::INFINITY
     }
 
+    /// Returns `true` if the number is [subnormal].
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
+    ///
+    /// let min = f16::MIN_POSITIVE; // 6.1035e-5
+    /// let max = f16::MAX;
+    /// let lower_than_min = 1.0e-7_f16;
+    /// let zero = 0.0_f16;
+    ///
+    /// assert!(!min.is_subnormal());
+    /// assert!(!max.is_subnormal());
+    ///
+    /// assert!(!zero.is_subnormal());
+    /// assert!(!f16::NAN.is_subnormal());
+    /// assert!(!f16::INFINITY.is_subnormal());
+    /// // Values between `0` and `min` are Subnormal.
+    /// assert!(lower_than_min.is_subnormal());
+    /// # }
+    /// ```
+    /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+    #[inline]
+    #[must_use]
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    pub const fn is_subnormal(self) -> bool {
+        matches!(self.classify(), FpCategory::Subnormal)
+    }
+
+    /// Returns `true` if the number is neither zero, infinite, [subnormal], or NaN.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
+    ///
+    /// let min = f16::MIN_POSITIVE; // 6.1035e-5
+    /// let max = f16::MAX;
+    /// let lower_than_min = 1.0e-7_f16;
+    /// let zero = 0.0_f16;
+    ///
+    /// assert!(min.is_normal());
+    /// assert!(max.is_normal());
+    ///
+    /// assert!(!zero.is_normal());
+    /// assert!(!f16::NAN.is_normal());
+    /// assert!(!f16::INFINITY.is_normal());
+    /// // Values between `0` and `min` are Subnormal.
+    /// assert!(!lower_than_min.is_normal());
+    /// # }
+    /// ```
+    /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+    #[inline]
+    #[must_use]
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    pub const fn is_normal(self) -> bool {
+        matches!(self.classify(), FpCategory::Normal)
+    }
+
+    /// Returns the floating point category of the number. If only one property
+    /// is going to be tested, it is generally faster to use the specific
+    /// predicate instead.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
+    ///
+    /// use std::num::FpCategory;
+    ///
+    /// let num = 12.4_f16;
+    /// let inf = f16::INFINITY;
+    ///
+    /// assert_eq!(num.classify(), FpCategory::Normal);
+    /// assert_eq!(inf.classify(), FpCategory::Infinite);
+    /// # }
+    /// ```
+    #[inline]
+    #[cfg(not(bootstrap))]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    pub const fn classify(self) -> FpCategory {
+        // A previous implementation for f32/f64 tried to only use bitmask-based checks,
+        // using `to_bits` to transmute the float to its bit repr and match on that.
+        // Unfortunately, floating point numbers can be much worse than that.
+        // This also needs to not result in recursive evaluations of `to_bits`.
+        //
+
+        // Platforms without native support generally convert to `f32` to perform operations,
+        // and most of these platforms correctly round back to `f16` after each operation.
+        // However, some platforms have bugs where they keep the excess `f32` precision (e.g.
+        // WASM, see llvm/llvm-project#96437). This implementation makes a best-effort attempt
+        // to account for that excess precision.
+        if self.is_infinite() {
+            // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
+            FpCategory::Infinite
+        } else if self.is_nan() {
+            // And it may not be NaN, as it can simply be an "overextended" finite value.
+            FpCategory::Nan
+        } else {
+            // However, std can't simply compare to zero to check for zero, either,
+            // as correctness requires avoiding equality tests that may be Subnormal == -0.0
+            // because it may be wrong under "denormals are zero" and "flush to zero" modes.
+            // Most of std's targets don't use those, but they are used for thumbv7neon.
+            // So, this does use bitpattern matching for the rest.
+
+            // SAFETY: f16 to u16 is fine. Usually.
+            // If classify has gotten this far, the value is definitely in one of these categories.
+            unsafe { f16::partial_classify(self) }
+        }
+    }
+
+    /// This doesn't actually return a right answer for NaN on purpose,
+    /// seeing as how it cannot correctly discern between a floating point NaN,
+    /// and some normal floating point numbers truncated from an x87 FPU.
+    ///
+    /// # Safety
+    ///
+    /// This requires making sure you call this function for values it answers correctly on,
+    /// otherwise it returns a wrong answer. This is not important for memory safety per se,
+    /// but getting floats correct is important for not accidentally leaking const eval
+    /// runtime-deviating logic which may or may not be acceptable.
+    #[inline]
+    #[cfg(not(bootstrap))]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    const unsafe fn partial_classify(self) -> FpCategory {
+        // SAFETY: The caller is not asking questions for which this will tell lies.
+        let b = unsafe { mem::transmute::<f16, u16>(self) };
+        match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
+            (0, Self::EXP_MASK) => FpCategory::Infinite,
+            (0, 0) => FpCategory::Zero,
+            (_, 0) => FpCategory::Subnormal,
+            _ => FpCategory::Normal,
+        }
+    }
+
+    /// This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
+    /// FIXME(jubilee): In a just world, this would be the entire impl for classify,
+    /// plus a transmute. We do not live in a just world, but we can make it more so.
+    #[inline]
+    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    const fn classify_bits(b: u16) -> FpCategory {
+        match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
+            (0, Self::EXP_MASK) => FpCategory::Infinite,
+            (_, Self::EXP_MASK) => FpCategory::Nan,
+            (0, 0) => FpCategory::Zero,
+            (_, 0) => FpCategory::Subnormal,
+            _ => FpCategory::Normal,
+        }
+    }
+
     /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
     /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
     /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
@@ -353,12 +515,15 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
+    /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// let f = 7.0_f16;
     /// let g = -7.0_f16;
     ///
     /// assert!(f.is_sign_positive());
     /// assert!(!g.is_sign_positive());
+    /// # }
     /// ```
     #[inline]
     #[must_use]
@@ -376,12 +541,15 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
+    /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// let f = 7.0_f16;
     /// let g = -7.0_f16;
     ///
     /// assert!(!f.is_sign_negative());
     /// assert!(g.is_sign_negative());
+    /// # }
     /// ```
     #[inline]
     #[must_use]
@@ -628,12 +796,52 @@ impl f16 {
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
-    pub fn to_bits(self) -> u16 {
-        // SAFETY: `u16` is a plain old datatype so we can always... uh...
-        // ...look, just pretend you forgot what you just read.
-        // Stability concerns.
-        unsafe { mem::transmute(self) }
+    pub const fn to_bits(self) -> u16 {
+        // SAFETY: `u16` is a plain old datatype so we can always transmute to it.
+        // ...sorta.
+        //
+        // It turns out that at runtime, it is possible for a floating point number
+        // to be subject to a floating point mode that alters nonzero subnormal numbers
+        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+        //
+        // And, of course evaluating to a NaN value is fairly nondeterministic.
+        // More precisely: when NaN should be returned is knowable, but which NaN?
+        // So far that's defined by a combination of LLVM and the CPU, not Rust.
+        // This function, however, allows observing the bitstring of a NaN,
+        // thus introspection on CTFE.
+        //
+        // In order to preserve, at least for the moment, const-to-runtime equivalence,
+        // we reject any of these possible situations from happening.
+        #[inline]
+        #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+        const fn ct_f16_to_u16(ct: f16) -> u16 {
+            // FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but we don't yet
+            // want to rely on that on all platforms because it is nondeterministic (e.g. x86 has
+            // convention discrepancies calling intrinsics). So just classify the bits instead.
+
+            // SAFETY: this is a POD transmutation
+            let bits = unsafe { mem::transmute::<f16, u16>(ct) };
+            match f16::classify_bits(bits) {
+                FpCategory::Nan => {
+                    panic!("const-eval error: cannot use f16::to_bits on a NaN")
+                }
+                FpCategory::Subnormal => {
+                    panic!("const-eval error: cannot use f16::to_bits on a subnormal number")
+                }
+                FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits,
+            }
+        }
+
+        #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+        fn rt_f16_to_u16(x: f16) -> u16 {
+            // SAFETY: `u16` is a plain old datatype so we can always... uh...
+            // ...look, just pretend you forgot what you just read.
+            // Stability concerns.
+            unsafe { mem::transmute(x) }
+        }
+        intrinsics::const_eval_select((self,), ct_f16_to_u16, rt_f16_to_u16)
     }
 
     /// Raw transmutation from `u16`.
@@ -677,11 +885,52 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    pub fn from_bits(v: u16) -> Self {
-        // SAFETY: `u16` is a plain old datatype so we can always... uh...
-        // ...look, just pretend you forgot what you just read.
-        // Stability concerns.
-        unsafe { mem::transmute(v) }
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+    pub const fn from_bits(v: u16) -> Self {
+        // It turns out the safety issues with sNaN were overblown! Hooray!
+        // SAFETY: `u16` is a plain old datatype so we can always transmute from it
+        // ...sorta.
+        //
+        // It turns out that at runtime, it is possible for a floating point number
+        // to be subject to floating point modes that alter nonzero subnormal numbers
+        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
+        // This is not a problem usually, but at least one tier2 platform for Rust
+        // actually exhibits this behavior by default: thumbv7neon
+        // aka "the Neon FPU in AArch32 state"
+        //
+        // And, of course evaluating to a NaN value is fairly nondeterministic.
+        // More precisely: when NaN should be returned is knowable, but which NaN?
+        // So far that's defined by a combination of LLVM and the CPU, not Rust.
+        // This function, however, allows observing the bitstring of a NaN,
+        // thus introspection on CTFE.
+        //
+        // In order to preserve, at least for the moment, const-to-runtime equivalence,
+        // reject any of these possible situations from happening.
+        #[inline]
+        #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+        const fn ct_u16_to_f16(ct: u16) -> f16 {
+            match f16::classify_bits(ct) {
+                FpCategory::Subnormal => {
+                    panic!("const-eval error: cannot use f16::from_bits on a subnormal number")
+                }
+                FpCategory::Nan => {
+                    panic!("const-eval error: cannot use f16::from_bits on NaN")
+                }
+                FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
+                    // SAFETY: It's not a frumious number
+                    unsafe { mem::transmute::<u16, f16>(ct) }
+                }
+            }
+        }
+
+        #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+        fn rt_u16_to_f16(x: u16) -> f16 {
+            // SAFETY: `u16` is a plain old datatype so we can always... uh...
+            // ...look, just pretend you forgot what you just read.
+            // Stability concerns.
+            unsafe { mem::transmute(x) }
+        }
+        intrinsics::const_eval_select((v,), ct_u16_to_f16, rt_u16_to_f16)
     }
 
     /// Return the memory representation of this floating point number as a byte array in
@@ -694,14 +943,18 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
+    /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// let bytes = 12.5f16.to_be_bytes();
     /// assert_eq!(bytes, [0x4a, 0x40]);
+    /// # }
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
-    pub fn to_be_bytes(self) -> [u8; 2] {
+    pub const fn to_be_bytes(self) -> [u8; 2] {
         self.to_bits().to_be_bytes()
     }
 
@@ -715,14 +968,18 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
+    /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// let bytes = 12.5f16.to_le_bytes();
     /// assert_eq!(bytes, [0x40, 0x4a]);
+    /// # }
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
-    pub fn to_le_bytes(self) -> [u8; 2] {
+    pub const fn to_le_bytes(self) -> [u8; 2] {
         self.to_bits().to_le_bytes()
     }
 
@@ -742,6 +999,8 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
+    /// # // FIXME(f16_f128): LLVM crashes on s390x, llvm/llvm-project#50374
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// let bytes = 12.5f16.to_ne_bytes();
     /// assert_eq!(
@@ -752,11 +1011,13 @@ impl f16 {
     ///         [0x40, 0x4a]
     ///     }
     /// );
+    /// # }
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
-    pub fn to_ne_bytes(self) -> [u8; 2] {
+    pub const fn to_ne_bytes(self) -> [u8; 2] {
         self.to_bits().to_ne_bytes()
     }
 
@@ -778,7 +1039,8 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    pub fn from_be_bytes(bytes: [u8; 2]) -> Self {
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+    pub const fn from_be_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_be_bytes(bytes))
     }
 
@@ -800,7 +1062,8 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    pub fn from_le_bytes(bytes: [u8; 2]) -> Self {
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+    pub const fn from_le_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_le_bytes(bytes))
     }
 
@@ -833,7 +1096,8 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    pub fn from_ne_bytes(bytes: [u8; 2]) -> Self {
+    #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
+    pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_ne_bytes(bytes))
     }
 
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 68cf8203433..3e7933e9eec 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -604,9 +604,9 @@ impl<T: ?Sized> *const T {
     ///
     /// * `self` and `origin` must either
     ///
+    ///   * point to the same address, or
     ///   * both be *derived from* a pointer to the same [allocated object], and the memory range between
-    ///     the two pointers must be either empty or in bounds of that object. (See below for an example.)
-    ///   * or both be derived from an integer literal/constant, and point to the same address.
+    ///     the two pointers must be in bounds of that object. (See below for an example.)
     ///
     /// * The distance between the pointers, in bytes, must be an exact multiple
     ///   of the size of `T`.
@@ -653,14 +653,14 @@ impl<T: ?Sized> *const T {
     /// let ptr1 = Box::into_raw(Box::new(0u8)) as *const u8;
     /// let ptr2 = Box::into_raw(Box::new(1u8)) as *const u8;
     /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
-    /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1.
-    /// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff);
+    /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1.
+    /// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff).wrapping_offset(1);
     /// assert_eq!(ptr2 as usize, ptr2_other as usize);
     /// // Since ptr2_other and ptr2 are derived from pointers to different objects,
     /// // computing their offset is undefined behavior, even though
-    /// // they point to the same address!
+    /// // they point to addresses that are in-bounds of the same object!
     /// unsafe {
-    ///     let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior
+    ///     let one = ptr2_other.offset_from(ptr2); // Undefined Behavior! ⚠️
     /// }
     /// ```
     #[stable(feature = "ptr_offset_from", since = "1.47.0")]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 0dc910db5b9..904d6c62dcf 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -829,9 +829,9 @@ impl<T: ?Sized> *mut T {
     ///
     /// * `self` and `origin` must either
     ///
+    ///   * point to the same address, or
     ///   * both be *derived from* a pointer to the same [allocated object], and the memory range between
-    ///     the two pointers must be either empty or in bounds of that object. (See below for an example.)
-    ///   * or both be derived from an integer literal/constant, and point to the same address.
+    ///     the two pointers must be in bounds of that object. (See below for an example.)
     ///
     /// * The distance between the pointers, in bytes, must be an exact multiple
     ///   of the size of `T`.
@@ -878,14 +878,14 @@ impl<T: ?Sized> *mut T {
     /// let ptr1 = Box::into_raw(Box::new(0u8));
     /// let ptr2 = Box::into_raw(Box::new(1u8));
     /// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
-    /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1.
-    /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff);
+    /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1.
+    /// let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff).wrapping_offset(1);
     /// assert_eq!(ptr2 as usize, ptr2_other as usize);
     /// // Since ptr2_other and ptr2 are derived from pointers to different objects,
     /// // computing their offset is undefined behavior, even though
-    /// // they point to the same address!
+    /// // they point to addresses that are in-bounds of the same object!
     /// unsafe {
-    ///     let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior
+    ///     let one = ptr2_other.offset_from(ptr2); // Undefined Behavior! ⚠️
     /// }
     /// ```
     #[stable(feature = "ptr_offset_from", since = "1.47.0")]
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 75a99e14fda..796c85d0cac 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -735,9 +735,9 @@ impl<T: ?Sized> NonNull<T> {
     ///
     /// * `self` and `origin` must either
     ///
+    ///   * point to the same address, or
     ///   * both be *derived from* a pointer to the same [allocated object], and the memory range between
-    ///     the two pointers must be either empty or in bounds of that object. (See below for an example.)
-    ///   * or both be derived from an integer literal/constant, and point to the same address.
+    ///     the two pointers must be in bounds of that object. (See below for an example.)
     ///
     /// * The distance between the pointers, in bytes, must be an exact multiple
     ///   of the size of `T`.
@@ -789,14 +789,15 @@ impl<T: ?Sized> NonNull<T> {
     /// let ptr1 = NonNull::new(Box::into_raw(Box::new(0u8))).unwrap();
     /// let ptr2 = NonNull::new(Box::into_raw(Box::new(1u8))).unwrap();
     /// let diff = (ptr2.addr().get() as isize).wrapping_sub(ptr1.addr().get() as isize);
-    /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1.
-    /// let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff)).unwrap();
+    /// // Make ptr2_other an "alias" of ptr2.add(1), but derived from ptr1.
+    /// let diff_plus_1 = diff.wrapping_add(1);
+    /// let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff_plus_1)).unwrap();
     /// assert_eq!(ptr2.addr(), ptr2_other.addr());
     /// // Since ptr2_other and ptr2 are derived from pointers to different objects,
     /// // computing their offset is undefined behavior, even though
-    /// // they point to the same address!
+    /// // they point to addresses that are in-bounds of the same object!
     ///
-    /// let zero = unsafe { ptr2_other.offset_from(ptr2) }; // Undefined Behavior
+    /// let one = unsafe { ptr2_other.offset_from(ptr2) }; // Undefined Behavior! ⚠️
     /// ```
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -1663,6 +1664,8 @@ impl<T> NonNull<[T]> {
     /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized.
     /// # #[allow(unused_variables)]
     /// let slice: &mut [MaybeUninit<u8>] = unsafe { memory.as_uninit_slice_mut() };
+    /// # // Prevent leaks for Miri.
+    /// # unsafe { Global.deallocate(memory.cast(), Layout::new::<[u8; 32]>()); }
     /// # Ok::<_, std::alloc::AllocError>(())
     /// ```
     #[inline]
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index ca1920f9812..504676ce187 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -388,6 +388,9 @@ pub(super) trait SplitIter: DoubleEndedIterator {
 /// ```
 /// let slice = [10, 40, 33, 20];
 /// let mut iter = slice.split(|num| num % 3 == 0);
+/// assert_eq!(iter.next(), Some(&[10, 40][..]));
+/// assert_eq!(iter.next(), Some(&[20][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`split`]: slice::split
@@ -541,6 +544,9 @@ impl<T, P> FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {}
 /// ```
 /// let slice = [10, 40, 33, 20];
 /// let mut iter = slice.split_inclusive(|num| num % 3 == 0);
+/// assert_eq!(iter.next(), Some(&[10, 40, 33][..]));
+/// assert_eq!(iter.next(), Some(&[20][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`split_inclusive`]: slice::split_inclusive
@@ -914,7 +920,10 @@ impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> b
 ///
 /// ```
 /// let slice = [11, 22, 33, 0, 44, 55];
-/// let iter = slice.rsplit(|num| *num == 0);
+/// let mut iter = slice.rsplit(|num| *num == 0);
+/// assert_eq!(iter.next(), Some(&[44, 55][..]));
+/// assert_eq!(iter.next(), Some(&[11, 22, 33][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`rsplit`]: slice::rsplit
@@ -1134,7 +1143,10 @@ impl<T, I: SplitIter<Item = T>> Iterator for GenericSplitN<I> {
 ///
 /// ```
 /// let slice = [10, 40, 30, 20, 60, 50];
-/// let iter = slice.splitn(2, |num| *num % 3 == 0);
+/// let mut iter = slice.splitn(2, |num| *num % 3 == 0);
+/// assert_eq!(iter.next(), Some(&[10, 40][..]));
+/// assert_eq!(iter.next(), Some(&[20, 60, 50][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`splitn`]: slice::splitn
@@ -1175,7 +1187,10 @@ where
 ///
 /// ```
 /// let slice = [10, 40, 30, 20, 60, 50];
-/// let iter = slice.rsplitn(2, |num| *num % 3 == 0);
+/// let mut iter = slice.rsplitn(2, |num| *num % 3 == 0);
+/// assert_eq!(iter.next(), Some(&[50][..]));
+/// assert_eq!(iter.next(), Some(&[10, 40, 30, 20][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`rsplitn`]: slice::rsplitn
@@ -1300,7 +1315,11 @@ forward_iterator! { RSplitNMut: T, &'a mut [T] }
 ///
 /// ```
 /// let slice = ['r', 'u', 's', 't'];
-/// let iter = slice.windows(2);
+/// let mut iter = slice.windows(2);
+/// assert_eq!(iter.next(), Some(&['r', 'u'][..]));
+/// assert_eq!(iter.next(), Some(&['u', 's'][..]));
+/// assert_eq!(iter.next(), Some(&['s', 't'][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`windows`]: slice::windows
@@ -1448,7 +1467,11 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Windows<'a, T> {
 ///
 /// ```
 /// let slice = ['l', 'o', 'r', 'e', 'm'];
-/// let iter = slice.chunks(2);
+/// let mut iter = slice.chunks(2);
+/// assert_eq!(iter.next(), Some(&['l', 'o'][..]));
+/// assert_eq!(iter.next(), Some(&['r', 'e'][..]));
+/// assert_eq!(iter.next(), Some(&['m'][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`chunks`]: slice::chunks
@@ -1819,7 +1842,10 @@ unsafe impl<T> Sync for ChunksMut<'_, T> where T: Sync {}
 ///
 /// ```
 /// let slice = ['l', 'o', 'r', 'e', 'm'];
-/// let iter = slice.chunks_exact(2);
+/// let mut iter = slice.chunks_exact(2);
+/// assert_eq!(iter.next(), Some(&['l', 'o'][..]));
+/// assert_eq!(iter.next(), Some(&['r', 'e'][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`chunks_exact`]: slice::chunks_exact
@@ -2163,7 +2189,11 @@ unsafe impl<T> Sync for ChunksExactMut<'_, T> where T: Sync {}
 /// #![feature(array_windows)]
 ///
 /// let slice = [0, 1, 2, 3];
-/// let iter = slice.array_windows::<2>();
+/// let mut iter = slice.array_windows::<2>();
+/// assert_eq!(iter.next(), Some(&[0, 1]));
+/// assert_eq!(iter.next(), Some(&[1, 2]));
+/// assert_eq!(iter.next(), Some(&[2, 3]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`array_windows`]: slice::array_windows
@@ -2285,7 +2315,10 @@ impl<T, const N: usize> ExactSizeIterator for ArrayWindows<'_, T, N> {
 /// #![feature(array_chunks)]
 ///
 /// let slice = ['l', 'o', 'r', 'e', 'm'];
-/// let iter = slice.array_chunks::<2>();
+/// let mut iter = slice.array_chunks::<2>();
+/// assert_eq!(iter.next(), Some(&['l', 'o']));
+/// assert_eq!(iter.next(), Some(&['r', 'e']));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`array_chunks`]: slice::array_chunks
@@ -2526,7 +2559,11 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunksMu
 ///
 /// ```
 /// let slice = ['l', 'o', 'r', 'e', 'm'];
-/// let iter = slice.rchunks(2);
+/// let mut iter = slice.rchunks(2);
+/// assert_eq!(iter.next(), Some(&['e', 'm'][..]));
+/// assert_eq!(iter.next(), Some(&['o', 'r'][..]));
+/// assert_eq!(iter.next(), Some(&['l'][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`rchunks`]: slice::rchunks
@@ -2892,7 +2929,10 @@ unsafe impl<T> Sync for RChunksMut<'_, T> where T: Sync {}
 ///
 /// ```
 /// let slice = ['l', 'o', 'r', 'e', 'm'];
-/// let iter = slice.rchunks_exact(2);
+/// let mut iter = slice.rchunks_exact(2);
+/// assert_eq!(iter.next(), Some(&['e', 'm'][..]));
+/// assert_eq!(iter.next(), Some(&['o', 'r'][..]));
+/// assert_eq!(iter.next(), None);
 /// ```
 ///
 /// [`rchunks_exact`]: slice::rchunks_exact
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 521c3248204..68508e85f8e 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3959,17 +3959,8 @@ impl<T> [T] {
 
     /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
     ///
-    /// This is a safe wrapper around [`slice::align_to`], so has the same weak
-    /// postconditions as that method.  You're only assured that
-    /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`.
-    ///
-    /// Notably, all of the following are possible:
-    /// - `prefix.len() >= LANES`.
-    /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`.
-    /// - `suffix.len() >= LANES`.
-    ///
-    /// That said, this is a safe method, so if you're only writing safe code,
-    /// then this can at most cause incorrect logic, not unsoundness.
+    /// This is a safe wrapper around [`slice::align_to`], so inherits the same
+    /// guarantees as that method.
     ///
     /// # Panics
     ///
@@ -4033,17 +4024,8 @@ impl<T> [T] {
     /// Split a mutable slice into a mutable prefix, a middle of aligned SIMD types,
     /// and a mutable suffix.
     ///
-    /// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak
-    /// postconditions as that method.  You're only assured that
-    /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`.
-    ///
-    /// Notably, all of the following are possible:
-    /// - `prefix.len() >= LANES`.
-    /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`.
-    /// - `suffix.len() >= LANES`.
-    ///
-    /// That said, this is a safe method, so if you're only writing safe code,
-    /// then this can at most cause incorrect logic, not unsoundness.
+    /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same
+    /// guarantees as that method.
     ///
     /// This is the mutable version of [`slice::as_simd`]; see that for examples.
     ///
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 358510b8f77..b991b1cf22d 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -87,6 +87,10 @@ std_detect_file_io = ["std_detect/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"]
 std_detect_env_override = ["std_detect/std_detect_env_override"]
 
+# Enable using raw-dylib for Windows imports.
+# This will eventually be the default.
+windows_raw_dylib = []
+
 [package.metadata.fortanix-sgx]
 # Maximum possible number of threads when testing
 threads = 125
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index fcd1c307b5a..1f6a3e90479 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -1018,7 +1018,7 @@ where
         K: Borrow<Q>,
         Q: Hash + Eq,
     {
-        self.base.get_many_unchecked_mut(ks)
+        unsafe { self.base.get_many_unchecked_mut(ks) }
     }
 
     /// Returns `true` if the map contains a value for the specified key.
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 2f35e721610..36add02d68c 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -366,11 +366,8 @@ impl Error for VarError {
 #[rustc_deprecated_safe_2024]
 #[stable(feature = "env", since = "1.0.0")]
 pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
-    _set_var(key.as_ref(), value.as_ref())
-}
-
-unsafe fn _set_var(key: &OsStr, value: &OsStr) {
-    os_imp::setenv(key, value).unwrap_or_else(|e| {
+    let (key, value) = (key.as_ref(), value.as_ref());
+    unsafe { os_imp::setenv(key, value) }.unwrap_or_else(|e| {
         panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}")
     })
 }
@@ -433,11 +430,8 @@ unsafe fn _set_var(key: &OsStr, value: &OsStr) {
 #[rustc_deprecated_safe_2024]
 #[stable(feature = "env", since = "1.0.0")]
 pub unsafe fn remove_var<K: AsRef<OsStr>>(key: K) {
-    _remove_var(key.as_ref())
-}
-
-unsafe fn _remove_var(key: &OsStr) {
-    os_imp::unsetenv(key)
+    let key = key.as_ref();
+    unsafe { os_imp::unsetenv(key) }
         .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}"))
 }
 
diff --git a/library/std/src/f128/tests.rs b/library/std/src/f128/tests.rs
index bd7a921c502..0b3e485b0e7 100644
--- a/library/std/src/f128/tests.rs
+++ b/library/std/src/f128/tests.rs
@@ -3,6 +3,7 @@
 #![cfg(reliable_f128)]
 
 use crate::f128::consts;
+use crate::num::FpCategory as Fp;
 use crate::num::*;
 
 /// Smallest number
@@ -52,9 +53,8 @@ fn test_nan() {
     assert!(!nan.is_finite());
     assert!(nan.is_sign_positive());
     assert!(!nan.is_sign_negative());
-    // FIXME(f16_f128): classify
-    // assert!(!nan.is_normal());
-    // assert_eq!(Fp::Nan, nan.classify());
+    assert!(!nan.is_normal());
+    assert_eq!(Fp::Nan, nan.classify());
 }
 
 #[test]
@@ -65,9 +65,8 @@ fn test_infinity() {
     assert!(inf.is_sign_positive());
     assert!(!inf.is_sign_negative());
     assert!(!inf.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(!inf.is_normal());
-    // assert_eq!(Fp::Infinite, inf.classify());
+    assert!(!inf.is_normal());
+    assert_eq!(Fp::Infinite, inf.classify());
 }
 
 #[test]
@@ -78,9 +77,8 @@ fn test_neg_infinity() {
     assert!(!neg_inf.is_sign_positive());
     assert!(neg_inf.is_sign_negative());
     assert!(!neg_inf.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(!neg_inf.is_normal());
-    // assert_eq!(Fp::Infinite, neg_inf.classify());
+    assert!(!neg_inf.is_normal());
+    assert_eq!(Fp::Infinite, neg_inf.classify());
 }
 
 #[test]
@@ -92,9 +90,8 @@ fn test_zero() {
     assert!(zero.is_sign_positive());
     assert!(!zero.is_sign_negative());
     assert!(!zero.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(!zero.is_normal());
-    // assert_eq!(Fp::Zero, zero.classify());
+    assert!(!zero.is_normal());
+    assert_eq!(Fp::Zero, zero.classify());
 }
 
 #[test]
@@ -106,9 +103,8 @@ fn test_neg_zero() {
     assert!(!neg_zero.is_sign_positive());
     assert!(neg_zero.is_sign_negative());
     assert!(!neg_zero.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(!neg_zero.is_normal());
-    // assert_eq!(Fp::Zero, neg_zero.classify());
+    assert!(!neg_zero.is_normal());
+    assert_eq!(Fp::Zero, neg_zero.classify());
 }
 
 #[test]
@@ -120,9 +116,8 @@ fn test_one() {
     assert!(one.is_sign_positive());
     assert!(!one.is_sign_negative());
     assert!(!one.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(one.is_normal());
-    // assert_eq!(Fp::Normal, one.classify());
+    assert!(one.is_normal());
+    assert_eq!(Fp::Normal, one.classify());
 }
 
 #[test]
@@ -164,7 +159,40 @@ fn test_is_finite() {
     assert!((-109.2f128).is_finite());
 }
 
-// FIXME(f16_f128): add `test_is_normal` and `test_classify` when classify is working
+#[test]
+fn test_is_normal() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    let zero: f128 = 0.0f128;
+    let neg_zero: f128 = -0.0;
+    assert!(!nan.is_normal());
+    assert!(!inf.is_normal());
+    assert!(!neg_inf.is_normal());
+    assert!(!zero.is_normal());
+    assert!(!neg_zero.is_normal());
+    assert!(1f128.is_normal());
+    assert!(1e-4931f128.is_normal());
+    assert!(!1e-4932f128.is_normal());
+}
+
+#[test]
+fn test_classify() {
+    let nan: f128 = f128::NAN;
+    let inf: f128 = f128::INFINITY;
+    let neg_inf: f128 = f128::NEG_INFINITY;
+    let zero: f128 = 0.0f128;
+    let neg_zero: f128 = -0.0;
+    assert_eq!(nan.classify(), Fp::Nan);
+    assert_eq!(inf.classify(), Fp::Infinite);
+    assert_eq!(neg_inf.classify(), Fp::Infinite);
+    assert_eq!(zero.classify(), Fp::Zero);
+    assert_eq!(neg_zero.classify(), Fp::Zero);
+    assert_eq!(1f128.classify(), Fp::Normal);
+    assert_eq!(1e-4931f128.classify(), Fp::Normal);
+    assert_eq!(1e-4932f128.classify(), Fp::Subnormal);
+}
+
 // FIXME(f16_f128): add missing math functions when available
 
 #[test]
diff --git a/library/std/src/f16/tests.rs b/library/std/src/f16/tests.rs
index bb6a811529e..26658a0be87 100644
--- a/library/std/src/f16/tests.rs
+++ b/library/std/src/f16/tests.rs
@@ -3,6 +3,7 @@
 #![cfg(reliable_f16)]
 
 use crate::f16::consts;
+use crate::num::FpCategory as Fp;
 use crate::num::*;
 
 // We run out of precision pretty quickly with f16
@@ -58,9 +59,8 @@ fn test_nan() {
     assert!(!nan.is_finite());
     assert!(nan.is_sign_positive());
     assert!(!nan.is_sign_negative());
-    // FIXME(f16_f128): classify
-    // assert!(!nan.is_normal());
-    // assert_eq!(Fp::Nan, nan.classify());
+    assert!(!nan.is_normal());
+    assert_eq!(Fp::Nan, nan.classify());
 }
 
 #[test]
@@ -71,9 +71,8 @@ fn test_infinity() {
     assert!(inf.is_sign_positive());
     assert!(!inf.is_sign_negative());
     assert!(!inf.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(!inf.is_normal());
-    // assert_eq!(Fp::Infinite, inf.classify());
+    assert!(!inf.is_normal());
+    assert_eq!(Fp::Infinite, inf.classify());
 }
 
 #[test]
@@ -84,9 +83,8 @@ fn test_neg_infinity() {
     assert!(!neg_inf.is_sign_positive());
     assert!(neg_inf.is_sign_negative());
     assert!(!neg_inf.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(!neg_inf.is_normal());
-    // assert_eq!(Fp::Infinite, neg_inf.classify());
+    assert!(!neg_inf.is_normal());
+    assert_eq!(Fp::Infinite, neg_inf.classify());
 }
 
 #[test]
@@ -98,9 +96,8 @@ fn test_zero() {
     assert!(zero.is_sign_positive());
     assert!(!zero.is_sign_negative());
     assert!(!zero.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(!zero.is_normal());
-    // assert_eq!(Fp::Zero, zero.classify());
+    assert!(!zero.is_normal());
+    assert_eq!(Fp::Zero, zero.classify());
 }
 
 #[test]
@@ -112,9 +109,8 @@ fn test_neg_zero() {
     assert!(!neg_zero.is_sign_positive());
     assert!(neg_zero.is_sign_negative());
     assert!(!neg_zero.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(!neg_zero.is_normal());
-    // assert_eq!(Fp::Zero, neg_zero.classify());
+    assert!(!neg_zero.is_normal());
+    assert_eq!(Fp::Zero, neg_zero.classify());
 }
 
 #[test]
@@ -126,9 +122,8 @@ fn test_one() {
     assert!(one.is_sign_positive());
     assert!(!one.is_sign_negative());
     assert!(!one.is_nan());
-    // FIXME(f16_f128): classify
-    // assert!(one.is_normal());
-    // assert_eq!(Fp::Normal, one.classify());
+    assert!(one.is_normal());
+    assert_eq!(Fp::Normal, one.classify());
 }
 
 #[test]
@@ -170,7 +165,40 @@ fn test_is_finite() {
     assert!((-109.2f16).is_finite());
 }
 
-// FIXME(f16_f128): add `test_is_normal` and `test_classify` when classify is working
+#[test]
+fn test_is_normal() {
+    let nan: f16 = f16::NAN;
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    let zero: f16 = 0.0f16;
+    let neg_zero: f16 = -0.0;
+    assert!(!nan.is_normal());
+    assert!(!inf.is_normal());
+    assert!(!neg_inf.is_normal());
+    assert!(!zero.is_normal());
+    assert!(!neg_zero.is_normal());
+    assert!(1f16.is_normal());
+    assert!(1e-4f16.is_normal());
+    assert!(!1e-5f16.is_normal());
+}
+
+#[test]
+fn test_classify() {
+    let nan: f16 = f16::NAN;
+    let inf: f16 = f16::INFINITY;
+    let neg_inf: f16 = f16::NEG_INFINITY;
+    let zero: f16 = 0.0f16;
+    let neg_zero: f16 = -0.0;
+    assert_eq!(nan.classify(), Fp::Nan);
+    assert_eq!(inf.classify(), Fp::Infinite);
+    assert_eq!(neg_inf.classify(), Fp::Infinite);
+    assert_eq!(zero.classify(), Fp::Zero);
+    assert_eq!(neg_zero.classify(), Fp::Zero);
+    assert_eq!(1f16.classify(), Fp::Normal);
+    assert_eq!(1e-4f16.classify(), Fp::Normal);
+    assert_eq!(1e-5f16.classify(), Fp::Subnormal);
+}
+
 // FIXME(f16_f128): add missing math functions when available
 
 #[test]
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index f8c66a3e717..1ca2b32e241 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -520,7 +520,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ln(self) -> f64 {
-        crate::sys::log_wrapper(self, |n| unsafe { intrinsics::logf64(n) })
+        unsafe { intrinsics::logf64(self) }
     }
 
     /// Returns the logarithm of the number with respect to an arbitrary base.
@@ -574,7 +574,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn log2(self) -> f64 {
-        crate::sys::log_wrapper(self, crate::sys::log2f64)
+        crate::sys::log2f64(self)
     }
 
     /// Returns the base 10 logarithm of the number.
@@ -599,7 +599,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn log10(self) -> f64 {
-        crate::sys::log_wrapper(self, |n| unsafe { intrinsics::log10f64(n) })
+        unsafe { intrinsics::log10f64(self) }
     }
 
     /// The positive difference of two numbers.
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 4a417c84a30..f9dba08da4c 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -184,7 +184,7 @@ impl OsString {
     #[inline]
     #[stable(feature = "os_str_bytes", since = "1.74.0")]
     pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec<u8>) -> Self {
-        OsString { inner: Buf::from_encoded_bytes_unchecked(bytes) }
+        OsString { inner: unsafe { Buf::from_encoded_bytes_unchecked(bytes) } }
     }
 
     /// Converts to an [`OsStr`] slice.
@@ -813,7 +813,7 @@ impl OsStr {
     #[inline]
     #[stable(feature = "os_str_bytes", since = "1.74.0")]
     pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self {
-        Self::from_inner(Slice::from_encoded_bytes_unchecked(bytes))
+        Self::from_inner(unsafe { Slice::from_encoded_bytes_unchecked(bytes) })
     }
 
     #[inline]
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index b75579d6d5e..5ca631399aa 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1638,16 +1638,8 @@ fn rename_directory() {
 
 #[test]
 fn test_file_times() {
-    #[cfg(target_os = "ios")]
-    use crate::os::ios::fs::FileTimesExt;
-    #[cfg(target_os = "macos")]
-    use crate::os::macos::fs::FileTimesExt;
-    #[cfg(target_os = "tvos")]
-    use crate::os::tvos::fs::FileTimesExt;
-    #[cfg(target_os = "visionos")]
-    use crate::os::visionos::fs::FileTimesExt;
-    #[cfg(target_os = "watchos")]
-    use crate::os::watchos::fs::FileTimesExt;
+    #[cfg(target_vendor = "apple")]
+    use crate::os::darwin::fs::FileTimesExt;
     #[cfg(windows)]
     use crate::os::windows::fs::FileTimesExt;
 
@@ -1693,16 +1685,7 @@ fn test_file_times() {
 #[test]
 #[cfg(target_vendor = "apple")]
 fn test_file_times_pre_epoch_with_nanos() {
-    #[cfg(target_os = "ios")]
-    use crate::os::ios::fs::FileTimesExt;
-    #[cfg(target_os = "macos")]
-    use crate::os::macos::fs::FileTimesExt;
-    #[cfg(target_os = "tvos")]
-    use crate::os::tvos::fs::FileTimesExt;
-    #[cfg(target_os = "visionos")]
-    use crate::os::visionos::fs::FileTimesExt;
-    #[cfg(target_os = "watchos")]
-    use crate::os::watchos::fs::FileTimesExt;
+    use crate::os::darwin::fs::FileTimesExt;
 
     let tmp = tmpdir();
     let file = File::create(tmp.join("foo")).unwrap();
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
index 2d13230ffba..a8680e9b6ea 100644
--- a/library/std/src/io/buffered/bufwriter.rs
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -3,7 +3,7 @@ use crate::fmt;
 use crate::io::{
     self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
 };
-use crate::mem;
+use crate::mem::{self, ManuallyDrop};
 use crate::ptr;
 
 /// Wraps a writer and buffers its output.
@@ -164,13 +164,13 @@ impl<W: Write> BufWriter<W> {
     /// assert_eq!(&buffered_data.unwrap(), b"ata");
     /// ```
     #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
-    pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
-        let buf = mem::take(&mut self.buf);
-        let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
+    pub fn into_parts(self) -> (W, Result<Vec<u8>, WriterPanicked>) {
+        let mut this = ManuallyDrop::new(self);
+        let buf = mem::take(&mut this.buf);
+        let buf = if !this.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
 
-        // SAFETY: forget(self) prevents double dropping inner
-        let inner = unsafe { ptr::read(&self.inner) };
-        mem::forget(self);
+        // SAFETY: double-drops are prevented by putting `this` in a ManuallyDrop that is never dropped
+        let inner = unsafe { ptr::read(&this.inner) };
 
         (inner, buf)
     }
@@ -433,9 +433,11 @@ impl<W: ?Sized + Write> BufWriter<W> {
         let old_len = self.buf.len();
         let buf_len = buf.len();
         let src = buf.as_ptr();
-        let dst = self.buf.as_mut_ptr().add(old_len);
-        ptr::copy_nonoverlapping(src, dst, buf_len);
-        self.buf.set_len(old_len + buf_len);
+        unsafe {
+            let dst = self.buf.as_mut_ptr().add(old_len);
+            ptr::copy_nonoverlapping(src, dst, buf_len);
+            self.buf.set_len(old_len + buf_len);
+        }
     }
 
     #[inline]
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index ee0db30e22c..ab66deaf31d 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -1067,3 +1067,13 @@ fn bufreader_full_initialize() {
     // But we initialized the whole buffer!
     assert_eq!(reader.initialized(), reader.capacity());
 }
+
+/// This is a regression test for https://github.com/rust-lang/rust/issues/127584.
+#[test]
+fn bufwriter_aliasing() {
+    use crate::io::{BufWriter, Cursor};
+    let mut v = vec![0; 1024];
+    let c = Cursor::new(&mut v);
+    let w = BufWriter::new(Box::new(c));
+    let _ = w.into_parts();
+}
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index a1a8b2a3505..2ed64a40495 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -482,7 +482,7 @@ where
     A: Allocator,
 {
     debug_assert!(vec.capacity() >= pos + buf.len());
-    vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len());
+    unsafe { vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()) };
     pos + buf.len()
 }
 
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index a5cefe2292b..fbb74967df3 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -267,11 +267,14 @@ where
                 // Using this rather than unwrap meaningfully improves the code
                 // for callers which only care about one variant (usually
                 // `Custom`)
-                core::hint::unreachable_unchecked();
+                unsafe { core::hint::unreachable_unchecked() };
             });
             ErrorData::Simple(kind)
         }
-        TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
+        TAG_SIMPLE_MESSAGE => {
+            // SAFETY: per tag
+            unsafe { ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()) }
+        }
         TAG_CUSTOM => {
             // It would be correct for us to use `ptr::byte_sub` here (see the
             // comment above the `wrapping_add` call in `new_custom` for why),
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 97b72f9664b..1345a30361e 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -382,11 +382,11 @@ pub(crate) unsafe fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize
 where
     F: FnOnce(&mut Vec<u8>) -> Result<usize>,
 {
-    let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
+    let mut g = Guard { len: buf.len(), buf: unsafe { buf.as_mut_vec() } };
     let ret = f(g.buf);
 
     // SAFETY: the caller promises to only append data to `buf`
-    let appended = g.buf.get_unchecked(g.len..);
+    let appended = unsafe { g.buf.get_unchecked(g.len..) };
     if str::from_utf8(appended).is_err() {
         ret.and_then(|_| Err(Error::INVALID_UTF8))
     } else {
@@ -1256,8 +1256,6 @@ impl<'a> IoSliceMut<'a> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(io_slice_advance)]
-    ///
     /// use std::io::IoSliceMut;
     /// use std::ops::Deref;
     ///
@@ -1268,7 +1266,7 @@ impl<'a> IoSliceMut<'a> {
     /// buf.advance(3);
     /// assert_eq!(buf.deref(), [1; 5].as_ref());
     /// ```
-    #[unstable(feature = "io_slice_advance", issue = "62726")]
+    #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub fn advance(&mut self, n: usize) {
         self.0.advance(n)
@@ -1290,8 +1288,6 @@ impl<'a> IoSliceMut<'a> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(io_slice_advance)]
-    ///
     /// use std::io::IoSliceMut;
     /// use std::ops::Deref;
     ///
@@ -1309,7 +1305,7 @@ impl<'a> IoSliceMut<'a> {
     /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
     /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
     /// ```
-    #[unstable(feature = "io_slice_advance", issue = "62726")]
+    #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
         // Number of buffers to remove.
@@ -1400,8 +1396,6 @@ impl<'a> IoSlice<'a> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(io_slice_advance)]
-    ///
     /// use std::io::IoSlice;
     /// use std::ops::Deref;
     ///
@@ -1412,7 +1406,7 @@ impl<'a> IoSlice<'a> {
     /// buf.advance(3);
     /// assert_eq!(buf.deref(), [1; 5].as_ref());
     /// ```
-    #[unstable(feature = "io_slice_advance", issue = "62726")]
+    #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub fn advance(&mut self, n: usize) {
         self.0.advance(n)
@@ -1434,8 +1428,6 @@ impl<'a> IoSlice<'a> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(io_slice_advance)]
-    ///
     /// use std::io::IoSlice;
     /// use std::ops::Deref;
     ///
@@ -1452,7 +1444,7 @@ impl<'a> IoSlice<'a> {
     /// IoSlice::advance_slices(&mut bufs, 10);
     /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
     /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
-    #[unstable(feature = "io_slice_advance", issue = "62726")]
+    #[stable(feature = "io_slice_advance", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
         // Number of buffers to remove.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 66aeb35acee..d4d68c2068d 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -252,6 +252,7 @@
 #![allow(internal_features)]
 #![deny(rustc::existing_doc_keyword)]
 #![deny(fuzzy_provenance_casts)]
+#![deny(unsafe_op_in_unsafe_fn)]
 #![allow(rustdoc::redundant_explicit_links)]
 // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
 #![deny(ffi_unwind_calls)]
@@ -664,7 +665,7 @@ pub mod alloc;
 mod panicking;
 
 #[path = "../../backtrace/src/lib.rs"]
-#[allow(dead_code, unused_attributes, fuzzy_provenance_casts)]
+#[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)]
 mod backtrace_rs;
 
 // Re-export macros defined in core.
diff --git a/library/std/src/os/macos/fs.rs b/library/std/src/os/darwin/fs.rs
index 573426d1a86..2032cca311a 100644
--- a/library/std/src/os/macos/fs.rs
+++ b/library/std/src/os/darwin/fs.rs
@@ -1,4 +1,4 @@
-#![stable(feature = "metadata_ext", since = "1.1.0")]
+#![allow(dead_code)]
 
 use crate::fs::{self, Metadata};
 use crate::sealed::Sealed;
@@ -6,7 +6,7 @@ use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
 use crate::time::SystemTime;
 
 #[allow(deprecated)]
-use crate::os::macos::raw;
+use super::raw;
 
 /// OS-specific extensions to [`fs::Metadata`].
 ///
@@ -70,6 +70,7 @@ pub trait MetadataExt {
     fn st_gen(&self) -> u32;
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_lspare(&self) -> u32;
+    #[cfg(target_os = "macos")]
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_qspare(&self) -> [u64; 2];
 }
@@ -143,6 +144,7 @@ impl MetadataExt for Metadata {
     fn st_lspare(&self) -> u32 {
         self.as_inner().as_inner().st_lspare as u32
     }
+    #[cfg(target_os = "macos")]
     fn st_qspare(&self) -> [u64; 2] {
         let qspare = self.as_inner().as_inner().st_qspare;
         [qspare[0] as u64, qspare[1] as u64]
diff --git a/library/std/src/os/darwin/mod.rs b/library/std/src/os/darwin/mod.rs
new file mode 100644
index 00000000000..03401fe8895
--- /dev/null
+++ b/library/std/src/os/darwin/mod.rs
@@ -0,0 +1,20 @@
+//! Platform-specific extensions to `std` for Darwin / Apple platforms.
+//!
+//! This is available on the following operating systems:
+//! - macOS
+//! - iOS
+//! - tvOS
+//! - watchOS
+//! - visionOS
+//!
+//! Note: This module is called "Darwin" as that's the name of the underlying
+//! core OS of the above operating systems, but it should not be confused with
+//! the `-darwin` suffix in the `x86_64-apple-darwin` and
+//! `aarch64-apple-darwin` target names, which are mostly named that way for
+//! legacy reasons.
+
+pub(crate) mod fs;
+// deprecated, but used for public reexport under `std::os::unix::raw`, as
+// well as `std::os::macos`/`std::os::ios`, because those modules precede the
+// decision to remove these.
+pub(super) mod raw;
diff --git a/library/std/src/os/ios/raw.rs b/library/std/src/os/darwin/raw.rs
index af12aeebe5d..047727f4532 100644
--- a/library/std/src/os/ios/raw.rs
+++ b/library/std/src/os/darwin/raw.rs
@@ -1,15 +1,4 @@
-//! iOS-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![deprecated(
-    since = "1.8.0",
-    note = "these type aliases are no longer supported by \
-            the standard library, the `libc` crate on \
-            crates.io should be used instead for the correct \
-            definitions"
-)]
-#![allow(deprecated)]
-
+//! Apple-specific raw type definitions
 use crate::os::raw::c_long;
 
 #[stable(feature = "raw_ext", since = "1.1.0")]
@@ -35,6 +24,7 @@ pub type pthread_t = usize;
 #[repr(C)]
 #[derive(Clone)]
 #[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(dead_code)]
 pub struct stat {
     #[stable(feature = "raw_ext", since = "1.1.0")]
     pub st_dev: i32,
diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs
deleted file mode 100644
index e5df4de0b7f..00000000000
--- a/library/std/src/os/ios/fs.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-#![stable(feature = "metadata_ext", since = "1.1.0")]
-
-use crate::fs::{self, Metadata};
-use crate::sealed::Sealed;
-use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
-use crate::time::SystemTime;
-
-#[allow(deprecated)]
-use super::raw;
-
-/// OS-specific extensions to [`fs::Metadata`].
-///
-/// [`fs::Metadata`]: crate::fs::Metadata
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Gain a reference to the underlying `stat` structure which contains
-    /// the raw information returned by the OS.
-    ///
-    /// The contents of the returned `stat` are **not** consistent across
-    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
-    /// cross-Unix abstractions contained within the raw stat.
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[deprecated(
-        since = "1.8.0",
-        note = "deprecated in favor of the accessor \
-                methods of this trait"
-    )]
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat;
-
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_dev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ino(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mode(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_nlink(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_uid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_rdev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_size(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blksize(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blocks(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_flags(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gen(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_lspare(&self) -> u32;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat {
-        unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
-    }
-    fn st_dev(&self) -> u64 {
-        self.as_inner().as_inner().st_dev as u64
-    }
-    fn st_ino(&self) -> u64 {
-        self.as_inner().as_inner().st_ino as u64
-    }
-    fn st_mode(&self) -> u32 {
-        self.as_inner().as_inner().st_mode as u32
-    }
-    fn st_nlink(&self) -> u64 {
-        self.as_inner().as_inner().st_nlink as u64
-    }
-    fn st_uid(&self) -> u32 {
-        self.as_inner().as_inner().st_uid as u32
-    }
-    fn st_gid(&self) -> u32 {
-        self.as_inner().as_inner().st_gid as u32
-    }
-    fn st_rdev(&self) -> u64 {
-        self.as_inner().as_inner().st_rdev as u64
-    }
-    fn st_size(&self) -> u64 {
-        self.as_inner().as_inner().st_size as u64
-    }
-    fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
-    }
-    fn st_atime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_atime_nsec as i64
-    }
-    fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
-    }
-    fn st_mtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime_nsec as i64
-    }
-    fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
-    }
-    fn st_ctime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime_nsec as i64
-    }
-    fn st_birthtime(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime as i64
-    }
-    fn st_birthtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime_nsec as i64
-    }
-    fn st_blksize(&self) -> u64 {
-        self.as_inner().as_inner().st_blksize as u64
-    }
-    fn st_blocks(&self) -> u64 {
-        self.as_inner().as_inner().st_blocks as u64
-    }
-    fn st_gen(&self) -> u32 {
-        self.as_inner().as_inner().st_gen as u32
-    }
-    fn st_flags(&self) -> u32 {
-        self.as_inner().as_inner().st_flags as u32
-    }
-    fn st_lspare(&self) -> u32 {
-        self.as_inner().as_inner().st_lspare as u32
-    }
-}
-
-/// OS-specific extensions to [`fs::FileTimes`].
-#[stable(feature = "file_set_times", since = "1.75.0")]
-pub trait FileTimesExt: Sealed {
-    /// Set the creation time of a file.
-    #[stable(feature = "file_set_times", since = "1.75.0")]
-    fn set_created(self, t: SystemTime) -> Self;
-}
-
-#[stable(feature = "file_set_times", since = "1.75.0")]
-impl FileTimesExt for fs::FileTimes {
-    fn set_created(mut self, t: SystemTime) -> Self {
-        self.as_inner_mut().set_created(t.into_inner());
-        self
-    }
-}
diff --git a/library/std/src/os/ios/mod.rs b/library/std/src/os/ios/mod.rs
index fdefa1f6b21..5e130d77b7b 100644
--- a/library/std/src/os/ios/mod.rs
+++ b/library/std/src/os/ios/mod.rs
@@ -2,5 +2,29 @@
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
 
-pub mod fs;
-pub mod raw;
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub mod fs {
+    #[doc(inline)]
+    #[stable(feature = "file_set_times", since = "1.75.0")]
+    pub use crate::os::darwin::fs::FileTimesExt;
+
+    #[doc(inline)]
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    pub use crate::os::darwin::fs::MetadataExt;
+}
+
+/// iOS-specific raw type definitions
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[deprecated(
+    since = "1.8.0",
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
+)]
+#[allow(deprecated)]
+pub mod raw {
+    #[doc(inline)]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub use crate::os::darwin::raw::*;
+}
diff --git a/library/std/src/os/macos/mod.rs b/library/std/src/os/macos/mod.rs
index 791d703b142..3638406b180 100644
--- a/library/std/src/os/macos/mod.rs
+++ b/library/std/src/os/macos/mod.rs
@@ -2,5 +2,29 @@
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
 
-pub mod fs;
-pub mod raw;
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub mod fs {
+    #[doc(inline)]
+    #[stable(feature = "file_set_times", since = "1.75.0")]
+    pub use crate::os::darwin::fs::FileTimesExt;
+
+    #[doc(inline)]
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    pub use crate::os::darwin::fs::MetadataExt;
+}
+
+/// macOS-specific raw type definitions
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[deprecated(
+    since = "1.8.0",
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
+)]
+#[allow(deprecated)]
+pub mod raw {
+    #[doc(inline)]
+    #[stable(feature = "raw_ext", since = "1.1.0")]
+    pub use crate::os::darwin::raw::*;
+}
diff --git a/library/std/src/os/macos/raw.rs b/library/std/src/os/macos/raw.rs
deleted file mode 100644
index 0b21f6ee5e4..00000000000
--- a/library/std/src/os/macos/raw.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-//! macOS-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![deprecated(
-    since = "1.8.0",
-    note = "these type aliases are no longer supported by \
-            the standard library, the `libc` crate on \
-            crates.io should be used instead for the correct \
-            definitions"
-)]
-#![allow(deprecated)]
-
-use crate::os::raw::c_long;
-
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type blkcnt_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type blksize_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type dev_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type ino_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type mode_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type nlink_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type off_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type time_t = i64;
-
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub type pthread_t = usize;
-
-#[repr(C)]
-#[derive(Clone)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub struct stat {
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_dev: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mode: u16,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_nlink: u16,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ino: u64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_uid: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_gid: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_rdev: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_atime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_atime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mtime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mtime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ctime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ctime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_birthtime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_birthtime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_size: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_blocks: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_blksize: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_flags: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_gen: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_lspare: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_qspare: [i64; 2],
-}
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index d2a7b316b81..020a8b324f4 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -2,6 +2,7 @@
 
 #![stable(feature = "os", since = "1.0.0")]
 #![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
+#![allow(unsafe_op_in_unsafe_fn)]
 
 pub mod raw;
 
@@ -14,7 +15,7 @@ pub mod raw;
 // documented don't compile (missing things in `libc` which is empty),
 // so just omit them with an empty module and add the "unstable" attribute.
 
-// Unix, linux, wasi and windows are handled a bit differently.
+// unix, linux, wasi and windows are handled a bit differently.
 #[cfg(all(
     doc,
     any(
@@ -104,6 +105,8 @@ pub mod windows;
 pub mod aix;
 #[cfg(target_os = "android")]
 pub mod android;
+#[cfg(target_vendor = "apple")]
+pub(crate) mod darwin;
 #[cfg(target_os = "dragonfly")]
 pub mod dragonfly;
 #[cfg(target_os = "emscripten")]
@@ -144,19 +147,12 @@ pub mod redox;
 pub mod solaris;
 #[cfg(target_os = "solid_asp3")]
 pub mod solid;
-#[cfg(target_os = "tvos")]
-#[path = "ios/mod.rs"]
-pub(crate) mod tvos;
 #[cfg(target_os = "uefi")]
 pub mod uefi;
-#[cfg(target_os = "visionos")]
-pub(crate) mod visionos;
 #[cfg(target_os = "vita")]
 pub mod vita;
 #[cfg(target_os = "vxworks")]
 pub mod vxworks;
-#[cfg(target_os = "watchos")]
-pub(crate) mod watchos;
 #[cfg(target_os = "xous")]
 pub mod xous;
 
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index d7a622012a5..c6581b9c4c8 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -41,6 +41,8 @@ mod platform {
     pub use crate::os::aix::*;
     #[cfg(target_os = "android")]
     pub use crate::os::android::*;
+    #[cfg(target_vendor = "apple")]
+    pub(super) use crate::os::darwin::*;
     #[cfg(target_os = "dragonfly")]
     pub use crate::os::dragonfly::*;
     #[cfg(target_os = "emscripten")]
@@ -59,14 +61,10 @@ mod platform {
     pub use crate::os::hurd::*;
     #[cfg(target_os = "illumos")]
     pub use crate::os::illumos::*;
-    #[cfg(target_os = "ios")]
-    pub use crate::os::ios::*;
     #[cfg(target_os = "l4re")]
     pub use crate::os::l4re::*;
     #[cfg(target_os = "linux")]
     pub use crate::os::linux::*;
-    #[cfg(target_os = "macos")]
-    pub use crate::os::macos::*;
     #[cfg(target_os = "netbsd")]
     pub use crate::os::netbsd::*;
     #[cfg(target_os = "nto")]
@@ -77,16 +75,10 @@ mod platform {
     pub use crate::os::redox::*;
     #[cfg(target_os = "solaris")]
     pub use crate::os::solaris::*;
-    #[cfg(target_os = "tvos")]
-    pub use crate::os::tvos::*;
-    #[cfg(target_os = "visionos")]
-    pub use crate::os::visionos::*;
     #[cfg(target_os = "vita")]
     pub use crate::os::vita::*;
     #[cfg(target_os = "vxworks")]
     pub use crate::os::vxworks::*;
-    #[cfg(target_os = "watchos")]
-    pub use crate::os::watchos::*;
 }
 
 pub mod ffi;
diff --git a/library/std/src/os/visionos/fs.rs b/library/std/src/os/visionos/fs.rs
deleted file mode 100644
index e5df4de0b7f..00000000000
--- a/library/std/src/os/visionos/fs.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-#![stable(feature = "metadata_ext", since = "1.1.0")]
-
-use crate::fs::{self, Metadata};
-use crate::sealed::Sealed;
-use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
-use crate::time::SystemTime;
-
-#[allow(deprecated)]
-use super::raw;
-
-/// OS-specific extensions to [`fs::Metadata`].
-///
-/// [`fs::Metadata`]: crate::fs::Metadata
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Gain a reference to the underlying `stat` structure which contains
-    /// the raw information returned by the OS.
-    ///
-    /// The contents of the returned `stat` are **not** consistent across
-    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
-    /// cross-Unix abstractions contained within the raw stat.
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[deprecated(
-        since = "1.8.0",
-        note = "deprecated in favor of the accessor \
-                methods of this trait"
-    )]
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat;
-
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_dev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ino(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mode(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_nlink(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_uid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_rdev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_size(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blksize(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blocks(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_flags(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gen(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_lspare(&self) -> u32;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat {
-        unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
-    }
-    fn st_dev(&self) -> u64 {
-        self.as_inner().as_inner().st_dev as u64
-    }
-    fn st_ino(&self) -> u64 {
-        self.as_inner().as_inner().st_ino as u64
-    }
-    fn st_mode(&self) -> u32 {
-        self.as_inner().as_inner().st_mode as u32
-    }
-    fn st_nlink(&self) -> u64 {
-        self.as_inner().as_inner().st_nlink as u64
-    }
-    fn st_uid(&self) -> u32 {
-        self.as_inner().as_inner().st_uid as u32
-    }
-    fn st_gid(&self) -> u32 {
-        self.as_inner().as_inner().st_gid as u32
-    }
-    fn st_rdev(&self) -> u64 {
-        self.as_inner().as_inner().st_rdev as u64
-    }
-    fn st_size(&self) -> u64 {
-        self.as_inner().as_inner().st_size as u64
-    }
-    fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
-    }
-    fn st_atime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_atime_nsec as i64
-    }
-    fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
-    }
-    fn st_mtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime_nsec as i64
-    }
-    fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
-    }
-    fn st_ctime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime_nsec as i64
-    }
-    fn st_birthtime(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime as i64
-    }
-    fn st_birthtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime_nsec as i64
-    }
-    fn st_blksize(&self) -> u64 {
-        self.as_inner().as_inner().st_blksize as u64
-    }
-    fn st_blocks(&self) -> u64 {
-        self.as_inner().as_inner().st_blocks as u64
-    }
-    fn st_gen(&self) -> u32 {
-        self.as_inner().as_inner().st_gen as u32
-    }
-    fn st_flags(&self) -> u32 {
-        self.as_inner().as_inner().st_flags as u32
-    }
-    fn st_lspare(&self) -> u32 {
-        self.as_inner().as_inner().st_lspare as u32
-    }
-}
-
-/// OS-specific extensions to [`fs::FileTimes`].
-#[stable(feature = "file_set_times", since = "1.75.0")]
-pub trait FileTimesExt: Sealed {
-    /// Set the creation time of a file.
-    #[stable(feature = "file_set_times", since = "1.75.0")]
-    fn set_created(self, t: SystemTime) -> Self;
-}
-
-#[stable(feature = "file_set_times", since = "1.75.0")]
-impl FileTimesExt for fs::FileTimes {
-    fn set_created(mut self, t: SystemTime) -> Self {
-        self.as_inner_mut().set_created(t.into_inner());
-        self
-    }
-}
diff --git a/library/std/src/os/visionos/mod.rs b/library/std/src/os/visionos/mod.rs
deleted file mode 100644
index f4b061ffda8..00000000000
--- a/library/std/src/os/visionos/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! visionos-specific definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-pub mod fs;
-pub mod raw;
diff --git a/library/std/src/os/visionos/raw.rs b/library/std/src/os/visionos/raw.rs
deleted file mode 100644
index 2b3eca6f493..00000000000
--- a/library/std/src/os/visionos/raw.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-//! visionos-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![deprecated(
-    since = "1.8.0",
-    note = "these type aliases are no longer supported by \
-            the standard library, the `libc` crate on \
-            crates.io should be used instead for the correct \
-            definitions"
-)]
-#![allow(deprecated)]
-
-use crate::os::raw::c_long;
-
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type blkcnt_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type blksize_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type dev_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type ino_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type mode_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type nlink_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type off_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type time_t = i64;
-
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub type pthread_t = usize;
-
-#[repr(C)]
-#[derive(Clone)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub struct stat {
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_dev: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mode: u16,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_nlink: u16,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ino: u64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_uid: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_gid: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_rdev: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_atime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_atime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mtime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mtime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ctime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ctime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_birthtime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_birthtime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_size: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_blocks: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_blksize: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_flags: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_gen: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_lspare: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_qspare: [i64; 2],
-}
diff --git a/library/std/src/os/watchos/fs.rs b/library/std/src/os/watchos/fs.rs
deleted file mode 100644
index ee215dd5984..00000000000
--- a/library/std/src/os/watchos/fs.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-#![stable(feature = "metadata_ext", since = "1.1.0")]
-
-use crate::fs::{self, Metadata};
-use crate::sealed::Sealed;
-use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
-use crate::time::SystemTime;
-
-#[allow(deprecated)]
-use crate::os::watchos::raw;
-
-/// OS-specific extensions to [`fs::Metadata`].
-///
-/// [`fs::Metadata`]: crate::fs::Metadata
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Gain a reference to the underlying `stat` structure which contains
-    /// the raw information returned by the OS.
-    ///
-    /// The contents of the returned `stat` are **not** consistent across
-    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
-    /// cross-Unix abstractions contained within the raw stat.
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[deprecated(
-        since = "1.8.0",
-        note = "deprecated in favor of the accessor \
-                  methods of this trait"
-    )]
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat;
-
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_dev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ino(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mode(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_nlink(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_uid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_rdev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_size(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blksize(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blocks(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_flags(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gen(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_lspare(&self) -> u32;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat {
-        unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) }
-    }
-    fn st_dev(&self) -> u64 {
-        self.as_inner().as_inner().st_dev as u64
-    }
-    fn st_ino(&self) -> u64 {
-        self.as_inner().as_inner().st_ino as u64
-    }
-    fn st_mode(&self) -> u32 {
-        self.as_inner().as_inner().st_mode as u32
-    }
-    fn st_nlink(&self) -> u64 {
-        self.as_inner().as_inner().st_nlink as u64
-    }
-    fn st_uid(&self) -> u32 {
-        self.as_inner().as_inner().st_uid as u32
-    }
-    fn st_gid(&self) -> u32 {
-        self.as_inner().as_inner().st_gid as u32
-    }
-    fn st_rdev(&self) -> u64 {
-        self.as_inner().as_inner().st_rdev as u64
-    }
-    fn st_size(&self) -> u64 {
-        self.as_inner().as_inner().st_size as u64
-    }
-    fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
-    }
-    fn st_atime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_atime_nsec as i64
-    }
-    fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
-    }
-    fn st_mtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime_nsec as i64
-    }
-    fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
-    }
-    fn st_ctime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime_nsec as i64
-    }
-    fn st_birthtime(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime as i64
-    }
-    fn st_birthtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime_nsec as i64
-    }
-    fn st_blksize(&self) -> u64 {
-        self.as_inner().as_inner().st_blksize as u64
-    }
-    fn st_blocks(&self) -> u64 {
-        self.as_inner().as_inner().st_blocks as u64
-    }
-    fn st_gen(&self) -> u32 {
-        self.as_inner().as_inner().st_gen as u32
-    }
-    fn st_flags(&self) -> u32 {
-        self.as_inner().as_inner().st_flags as u32
-    }
-    fn st_lspare(&self) -> u32 {
-        self.as_inner().as_inner().st_lspare as u32
-    }
-}
-
-/// OS-specific extensions to [`fs::FileTimes`].
-#[stable(feature = "file_set_times", since = "1.75.0")]
-pub trait FileTimesExt: Sealed {
-    /// Set the creation time of a file.
-    #[stable(feature = "file_set_times", since = "1.75.0")]
-    fn set_created(self, t: SystemTime) -> Self;
-}
-
-#[stable(feature = "file_set_times", since = "1.75.0")]
-impl FileTimesExt for fs::FileTimes {
-    fn set_created(mut self, t: SystemTime) -> Self {
-        self.as_inner_mut().set_created(t.into_inner());
-        self
-    }
-}
diff --git a/library/std/src/os/watchos/mod.rs b/library/std/src/os/watchos/mod.rs
deleted file mode 100644
index cd6454ebbf9..00000000000
--- a/library/std/src/os/watchos/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! watchOS-specific definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-pub mod fs;
-pub mod raw;
diff --git a/library/std/src/os/watchos/raw.rs b/library/std/src/os/watchos/raw.rs
deleted file mode 100644
index 630a533d9aa..00000000000
--- a/library/std/src/os/watchos/raw.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-//! watchOS-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![deprecated(
-    since = "1.8.0",
-    note = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
-)]
-#![allow(deprecated)]
-
-use crate::os::raw::c_long;
-
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type blkcnt_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type blksize_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type dev_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type ino_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type mode_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type nlink_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type off_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type time_t = i64;
-
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub type pthread_t = usize;
-
-#[repr(C)]
-#[derive(Clone)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub struct stat {
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_dev: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mode: u16,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_nlink: u16,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ino: u64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_uid: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_gid: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_rdev: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_atime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_atime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mtime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mtime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ctime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ctime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_birthtime: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_birthtime_nsec: c_long,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_size: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_blocks: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_blksize: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_flags: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_gen: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_lspare: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_qspare: [i64; 2],
-}
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
index 770583a9ce3..343cc6e4a8a 100644
--- a/library/std/src/os/windows/io/raw.rs
+++ b/library/std/src/os/windows/io/raw.rs
@@ -159,10 +159,12 @@ fn stdio_handle(raw: RawHandle) -> RawHandle {
 impl FromRawHandle for fs::File {
     #[inline]
     unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
-        let handle = handle as sys::c::HANDLE;
-        fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner(
-            OwnedHandle::from_raw_handle(handle),
-        )))
+        unsafe {
+            let handle = handle as sys::c::HANDLE;
+            fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner(
+                OwnedHandle::from_raw_handle(handle),
+            )))
+        }
     }
 }
 
@@ -260,24 +262,30 @@ impl AsRawSocket for net::UdpSocket {
 impl FromRawSocket for net::TcpStream {
     #[inline]
     unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
-        let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
-        net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
+        unsafe {
+            let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+            net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
+        }
     }
 }
 #[stable(feature = "from_raw_os", since = "1.1.0")]
 impl FromRawSocket for net::TcpListener {
     #[inline]
     unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
-        let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
-        net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
+        unsafe {
+            let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+            net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
+        }
     }
 }
 #[stable(feature = "from_raw_os", since = "1.1.0")]
 impl FromRawSocket for net::UdpSocket {
     #[inline]
     unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
-        let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
-        net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
+        unsafe {
+            let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
+            net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
+        }
     }
 }
 
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index 6ffdf907c8e..4334d041439 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -76,7 +76,7 @@ impl BorrowedSocket<'_> {
     #[stable(feature = "io_safety", since = "1.63.0")]
     pub const unsafe fn borrow_raw(socket: RawSocket) -> Self {
         assert!(socket != sys::c::INVALID_SOCKET as RawSocket);
-        Self { socket, _phantom: PhantomData }
+        unsafe { Self { socket, _phantom: PhantomData } }
     }
 }
 
@@ -201,8 +201,10 @@ impl IntoRawSocket for OwnedSocket {
 impl FromRawSocket for OwnedSocket {
     #[inline]
     unsafe fn from_raw_socket(socket: RawSocket) -> Self {
-        debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket);
-        Self { socket }
+        unsafe {
+            debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket);
+            Self { socket }
+        }
     }
 }
 
diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs
index 52eb3b7c067..f452403ee84 100644
--- a/library/std/src/os/windows/mod.rs
+++ b/library/std/src/os/windows/mod.rs
@@ -24,6 +24,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![doc(cfg(windows))]
+#![deny(unsafe_op_in_unsafe_fn)]
 
 pub mod ffi;
 pub mod fs;
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 05ffb8925a1..3927b2ed9bb 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -16,7 +16,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 #[stable(feature = "process_extensions", since = "1.2.0")]
 impl FromRawHandle for process::Stdio {
     unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
-        let handle = sys::handle::Handle::from_raw_handle(handle as *mut _);
+        let handle = unsafe { sys::handle::Handle::from_raw_handle(handle as *mut _) };
         let io = sys::process::Stdio::Handle(handle);
         process::Stdio::from_inner(io)
     }
@@ -407,7 +407,7 @@ impl CommandExt for process::Command {
         attribute: usize,
         value: T,
     ) -> &mut process::Command {
-        self.as_inner_mut().raw_attribute(attribute, value);
+        unsafe { self.as_inner_mut().raw_attribute(attribute, value) };
         self
     }
 }
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index ebd05415695..418a855fb72 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -253,16 +253,20 @@ fn default_hook(info: &PanicHookInfo<'_>) {
     let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
 
     let write = |err: &mut dyn crate::io::Write| {
+        // Use a lock to prevent mixed output in multithreading context.
+        // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows.
+        let mut lock = backtrace::lock();
         let _ = writeln!(err, "thread '{name}' panicked at {location}:\n{msg}");
 
         static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
         match backtrace {
+            // SAFETY: we took out a lock just a second ago.
             Some(BacktraceStyle::Short) => {
-                drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Short))
+                drop(lock.print(err, crate::backtrace_rs::PrintFmt::Short))
             }
             Some(BacktraceStyle::Full) => {
-                drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Full))
+                drop(lock.print(err, crate::backtrace_rs::PrintFmt::Full))
             }
             Some(BacktraceStyle::Off) => {
                 if FIRST_PANIC.swap(false, Ordering::Relaxed) {
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index f351dab78dc..fc86578a5ff 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -96,9 +96,9 @@
 //! child processes must agree on how the commandline string is encoded.
 //!
 //! Most programs use the standard C run-time `argv`, which in practice results
-//! in consistent argument handling. However some programs have their own way of
+//! in consistent argument handling. However, some programs have their own way of
 //! parsing the commandline string. In these cases using [`arg`] or [`args`] may
-//! result in the child process seeing a different array of arguments then the
+//! result in the child process seeing a different array of arguments than the
 //! parent process intended.
 //!
 //! Two ways of mitigating this are:
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 63455a274fa..055601d0307 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -385,29 +385,25 @@ fn test_interior_nul_in_env_value_is_error() {
 #[cfg(windows)]
 fn test_creation_flags() {
     use crate::os::windows::process::CommandExt;
-    use crate::sys::c::{BOOL, DWORD, INFINITE};
-    #[repr(C, packed)]
+    use crate::sys::c::{BOOL, INFINITE};
+    #[repr(C)]
     struct DEBUG_EVENT {
-        pub event_code: DWORD,
-        pub process_id: DWORD,
-        pub thread_id: DWORD,
+        pub event_code: u32,
+        pub process_id: u32,
+        pub thread_id: u32,
         // This is a union in the real struct, but we don't
         // need this data for the purposes of this test.
         pub _junk: [u8; 164],
     }
 
     extern "system" {
-        fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL;
-        fn ContinueDebugEvent(
-            dwProcessId: DWORD,
-            dwThreadId: DWORD,
-            dwContinueStatus: DWORD,
-        ) -> BOOL;
+        fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: u32) -> BOOL;
+        fn ContinueDebugEvent(dwProcessId: u32, dwThreadId: u32, dwContinueStatus: u32) -> BOOL;
     }
 
-    const DEBUG_PROCESS: DWORD = 1;
-    const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5;
-    const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001;
+    const DEBUG_PROCESS: u32 = 1;
+    const EXIT_PROCESS_DEBUG_EVENT: u32 = 5;
+    const DBG_EXCEPTION_NOT_HANDLED: u32 = 0x80010001;
 
     let mut child =
         Command::new("cmd").creation_flags(DEBUG_PROCESS).stdin(Stdio::piped()).spawn().unwrap();
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index b03fa1c01f2..d030017cfb4 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -90,13 +90,14 @@ macro_rules! rtunwrap {
 // `compiler/rustc_session/src/config/sigpipe.rs`.
 #[cfg_attr(test, allow(dead_code))]
 unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
+    #[cfg_attr(target_os = "teeos", allow(unused_unsafe))]
     unsafe {
-        sys::init(argc, argv, sigpipe);
+        sys::init(argc, argv, sigpipe)
+    };
 
-        // Set up the current thread to give it the right name.
-        let thread = Thread::new_main();
-        thread::set_current(thread);
-    }
+    // Set up the current thread to give it the right name.
+    let thread = Thread::new_main();
+    thread::set_current(thread);
 }
 
 // One-time runtime cleanup.
@@ -144,6 +145,9 @@ fn lang_start_internal(
             rtabort!("drop of the panic payload panicked");
         });
     panic::catch_unwind(cleanup).map_err(rt_abort)?;
+    // Guard against multple threads calling `libc::exit` concurrently.
+    // See the documentation for `unique_thread_exit` for more information.
+    panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?;
     ret_code
 }
 
diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs
index f9f83fb4f63..08d46f356d9 100644
--- a/library/std/src/sync/condvar.rs
+++ b/library/std/src/sync/condvar.rs
@@ -35,6 +35,7 @@ impl WaitTimeoutResult {
     /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
     /// let pair2 = Arc::clone(&pair);
     ///
+    /// # let handle =
     /// thread::spawn(move || {
     ///     let (lock, cvar) = &*pair2;
     ///
@@ -58,6 +59,8 @@ impl WaitTimeoutResult {
     ///         break
     ///     }
     /// }
+    /// # // Prevent leaks for Miri.
+    /// # let _ = handle.join();
     /// ```
     #[must_use]
     #[stable(feature = "wait_timeout", since = "1.5.0")]
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index b70c041fa42..18906aceffa 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -107,7 +107,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(lazy_cell_consume)]
+    /// #![feature(lazy_cell_into_inner)]
     ///
     /// use std::sync::LazyLock;
     ///
@@ -118,7 +118,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// assert_eq!(&*lazy, "HELLO, WORLD!");
     /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
     /// ```
-    #[unstable(feature = "lazy_cell_consume", issue = "125623")]
+    #[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
     pub fn into_inner(mut this: Self) -> Result<T, F> {
         let state = this.once.state();
         match state {
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
index 492e21d9bdb..185319add74 100644
--- a/library/std/src/sync/mpmc/array.rs
+++ b/library/std/src/sync/mpmc/array.rs
@@ -200,11 +200,12 @@ impl<T> Channel<T> {
             return Err(msg);
         }
 
-        let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
-
         // Write the message into the slot and update the stamp.
-        slot.msg.get().write(MaybeUninit::new(msg));
-        slot.stamp.store(token.array.stamp, Ordering::Release);
+        unsafe {
+            let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
+            slot.msg.get().write(MaybeUninit::new(msg));
+            slot.stamp.store(token.array.stamp, Ordering::Release);
+        }
 
         // Wake a sleeping receiver.
         self.receivers.notify();
@@ -291,11 +292,14 @@ impl<T> Channel<T> {
             return Err(());
         }
 
-        let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
-
         // Read the message from the slot and update the stamp.
-        let msg = slot.msg.get().read().assume_init();
-        slot.stamp.store(token.array.stamp, Ordering::Release);
+        let msg = unsafe {
+            let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
+
+            let msg = slot.msg.get().read().assume_init();
+            slot.stamp.store(token.array.stamp, Ordering::Release);
+            msg
+        };
 
         // Wake a sleeping sender.
         self.senders.notify();
@@ -471,7 +475,7 @@ impl<T> Channel<T> {
             false
         };
 
-        self.discard_all_messages(tail);
+        unsafe { self.discard_all_messages(tail) };
         disconnected
     }
 
diff --git a/library/std/src/sync/mpmc/counter.rs b/library/std/src/sync/mpmc/counter.rs
index a5a6bdc67f1..3478cf41dc9 100644
--- a/library/std/src/sync/mpmc/counter.rs
+++ b/library/std/src/sync/mpmc/counter.rs
@@ -63,7 +63,7 @@ impl<C> Sender<C> {
             disconnect(&self.counter().chan);
 
             if self.counter().destroy.swap(true, Ordering::AcqRel) {
-                drop(Box::from_raw(self.counter));
+                drop(unsafe { Box::from_raw(self.counter) });
             }
         }
     }
@@ -116,7 +116,7 @@ impl<C> Receiver<C> {
             disconnect(&self.counter().chan);
 
             if self.counter().destroy.swap(true, Ordering::AcqRel) {
-                drop(Box::from_raw(self.counter));
+                drop(unsafe { Box::from_raw(self.counter) });
             }
         }
     }
diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs
index 9e7148c716c..edac7a0cb18 100644
--- a/library/std/src/sync/mpmc/list.rs
+++ b/library/std/src/sync/mpmc/list.rs
@@ -91,7 +91,7 @@ impl<T> Block<T> {
         // It is not necessary to set the `DESTROY` bit in the last slot because that slot has
         // begun destruction of the block.
         for i in start..BLOCK_CAP - 1 {
-            let slot = (*this).slots.get_unchecked(i);
+            let slot = unsafe { (*this).slots.get_unchecked(i) };
 
             // Mark the `DESTROY` bit if a thread is still using the slot.
             if slot.state.load(Ordering::Acquire) & READ == 0
@@ -103,7 +103,7 @@ impl<T> Block<T> {
         }
 
         // No thread is using the block, now it is safe to destroy it.
-        drop(Box::from_raw(this));
+        drop(unsafe { Box::from_raw(this) });
     }
 }
 
@@ -265,9 +265,11 @@ impl<T> Channel<T> {
         // Write the message into the slot.
         let block = token.list.block as *mut Block<T>;
         let offset = token.list.offset;
-        let slot = (*block).slots.get_unchecked(offset);
-        slot.msg.get().write(MaybeUninit::new(msg));
-        slot.state.fetch_or(WRITE, Ordering::Release);
+        unsafe {
+            let slot = (*block).slots.get_unchecked(offset);
+            slot.msg.get().write(MaybeUninit::new(msg));
+            slot.state.fetch_or(WRITE, Ordering::Release);
+        }
 
         // Wake a sleeping receiver.
         self.receivers.notify();
@@ -369,19 +371,21 @@ impl<T> Channel<T> {
         // Read the message.
         let block = token.list.block as *mut Block<T>;
         let offset = token.list.offset;
-        let slot = (*block).slots.get_unchecked(offset);
-        slot.wait_write();
-        let msg = slot.msg.get().read().assume_init();
-
-        // Destroy the block if we've reached the end, or if another thread wanted to destroy but
-        // couldn't because we were busy reading from the slot.
-        if offset + 1 == BLOCK_CAP {
-            Block::destroy(block, 0);
-        } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
-            Block::destroy(block, offset + 1);
-        }
+        unsafe {
+            let slot = (*block).slots.get_unchecked(offset);
+            slot.wait_write();
+            let msg = slot.msg.get().read().assume_init();
+
+            // Destroy the block if we've reached the end, or if another thread wanted to destroy but
+            // couldn't because we were busy reading from the slot.
+            if offset + 1 == BLOCK_CAP {
+                Block::destroy(block, 0);
+            } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
+                Block::destroy(block, offset + 1);
+            }
 
-        Ok(msg)
+            Ok(msg)
+        }
     }
 
     /// Attempts to send a message into the channel.
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
index 1b82713edc7..6d1c9d64e7a 100644
--- a/library/std/src/sync/mpmc/zero.rs
+++ b/library/std/src/sync/mpmc/zero.rs
@@ -103,9 +103,11 @@ impl<T> Channel<T> {
             return Err(msg);
         }
 
-        let packet = &*(token.zero.0 as *const Packet<T>);
-        packet.msg.get().write(Some(msg));
-        packet.ready.store(true, Ordering::Release);
+        unsafe {
+            let packet = &*(token.zero.0 as *const Packet<T>);
+            packet.msg.get().write(Some(msg));
+            packet.ready.store(true, Ordering::Release);
+        }
         Ok(())
     }
 
@@ -116,22 +118,24 @@ impl<T> Channel<T> {
             return Err(());
         }
 
-        let packet = &*(token.zero.0 as *const Packet<T>);
+        let packet = unsafe { &*(token.zero.0 as *const Packet<T>) };
 
         if packet.on_stack {
             // The message has been in the packet from the beginning, so there is no need to wait
             // for it. However, after reading the message, we need to set `ready` to `true` in
             // order to signal that the packet can be destroyed.
-            let msg = packet.msg.get().replace(None).unwrap();
+            let msg = unsafe { packet.msg.get().replace(None) }.unwrap();
             packet.ready.store(true, Ordering::Release);
             Ok(msg)
         } else {
             // Wait until the message becomes available, then read it and destroy the
             // heap-allocated packet.
             packet.wait_ready();
-            let msg = packet.msg.get().replace(None).unwrap();
-            drop(Box::from_raw(token.zero.0 as *mut Packet<T>));
-            Ok(msg)
+            unsafe {
+                let msg = packet.msg.get().replace(None).unwrap();
+                drop(Box::from_raw(token.zero.0 as *mut Packet<T>));
+                Ok(msg)
+            }
         }
     }
 
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index fe243550606..94955beaf37 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -502,7 +502,7 @@ impl<T> OnceLock<T> {
     #[inline]
     unsafe fn get_unchecked(&self) -> &T {
         debug_assert!(self.is_initialized());
-        (&*self.value.get()).assume_init_ref()
+        unsafe { (&*self.value.get()).assume_init_ref() }
     }
 
     /// # Safety
@@ -511,7 +511,7 @@ impl<T> OnceLock<T> {
     #[inline]
     unsafe fn get_unchecked_mut(&mut self) -> &mut T {
         debug_assert!(self.is_initialized());
-        (&mut *self.value.get()).assume_init_mut()
+        unsafe { (&mut *self.value.get()).assume_init_mut() }
     }
 }
 
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index f7fe8eb1c7f..042c439394e 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -244,7 +244,9 @@ impl<T: ?Sized> ReentrantLock<T> {
     }
 
     unsafe fn increment_lock_count(&self) -> Option<()> {
-        *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?;
+        unsafe {
+            *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?;
+        }
         Some(())
     }
 }
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index e0a8a7603d7..a4ec52a4abe 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -578,7 +578,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
     // successfully called from the same thread before instantiating this object.
     unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> {
         poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard {
-            data: NonNull::new_unchecked(lock.data.get()),
+            data: unsafe { NonNull::new_unchecked(lock.data.get()) },
             inner_lock: &lock.inner,
         })
     }
diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs
index 0b2338fd7de..7401d8ce320 100644
--- a/library/std/src/sys/backtrace.rs
+++ b/library/std/src/sys/backtrace.rs
@@ -7,44 +7,41 @@ use crate::fmt;
 use crate::io;
 use crate::io::prelude::*;
 use crate::path::{self, Path, PathBuf};
-use crate::sync::{Mutex, PoisonError};
+use crate::sync::{Mutex, MutexGuard, PoisonError};
 
 /// Max number of frames to print.
 const MAX_NB_FRAMES: usize = 100;
 
-pub fn lock() -> impl Drop {
+pub(crate) struct BacktraceLock<'a>(#[allow(dead_code)] MutexGuard<'a, ()>);
+
+pub(crate) fn lock<'a>() -> BacktraceLock<'a> {
     static LOCK: Mutex<()> = Mutex::new(());
-    LOCK.lock().unwrap_or_else(PoisonError::into_inner)
+    BacktraceLock(LOCK.lock().unwrap_or_else(PoisonError::into_inner))
 }
 
-/// Prints the current backtrace.
-pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
-    // There are issues currently linking libbacktrace into tests, and in
-    // general during std's own unit tests we're not testing this path. In
-    // test mode immediately return here to optimize away any references to the
-    // libbacktrace symbols
-    if cfg!(test) {
-        return Ok(());
-    }
-
-    // Use a lock to prevent mixed output in multithreading context.
-    // Some platforms also requires it, like `SymFromAddr` on Windows.
-    unsafe {
-        let _lock = lock();
-        _print(w, format)
-    }
-}
+impl BacktraceLock<'_> {
+    /// Prints the current backtrace.
+    ///
+    /// NOTE: this function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program.
+    pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
+        // There are issues currently linking libbacktrace into tests, and in
+        // general during std's own unit tests we're not testing this path. In
+        // test mode immediately return here to optimize away any references to the
+        // libbacktrace symbols
+        if cfg!(test) {
+            return Ok(());
+        }
 
-unsafe fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
-    struct DisplayBacktrace {
-        format: PrintFmt,
-    }
-    impl fmt::Display for DisplayBacktrace {
-        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-            unsafe { _print_fmt(fmt, self.format) }
+        struct DisplayBacktrace {
+            format: PrintFmt,
+        }
+        impl fmt::Display for DisplayBacktrace {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                unsafe { _print_fmt(fmt, self.format) }
+            }
         }
+        write!(w, "{}", DisplayBacktrace { format })
     }
-    write!(w, "{}", DisplayBacktrace { format })
 }
 
 unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs
new file mode 100644
index 00000000000..5a090f50666
--- /dev/null
+++ b/library/std/src/sys/exit_guard.rs
@@ -0,0 +1,72 @@
+cfg_if::cfg_if! {
+    if #[cfg(target_os = "linux")] {
+        /// pthread_t is a pointer on some platforms,
+        /// so we wrap it in this to impl Send + Sync.
+        #[derive(Clone, Copy)]
+        #[repr(transparent)]
+        struct PThread(libc::pthread_t);
+        // Safety: pthread_t is safe to send between threads
+        unsafe impl Send for PThread {}
+        // Safety: pthread_t is safe to share between threads
+        unsafe impl Sync for PThread {}
+        /// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
+        ///
+        /// On glibc, `libc::exit` has been observed to not always be thread-safe.
+        /// It is currently unclear whether that is a glibc bug or allowed by the standard.
+        /// To mitigate this problem, we ensure that only one
+        /// Rust thread calls `libc::exit` (or returns from `main`) by calling this function before
+        /// calling `libc::exit` (or returning from `main`).
+        ///
+        /// Technically, this is not enough to ensure soundness, since other code directly calling
+        /// `libc::exit` will still race with this.
+        ///
+        /// *This function does not itself call `libc::exit`.* This is so it can also be used
+        /// to guard returning from `main`.
+        ///
+        /// This function will return only the first time it is called in a process.
+        ///
+        /// * If it is called again on the same thread as the first call, it will abort.
+        /// * If it is called again on a different thread, it will wait in a loop
+        ///   (waiting for the process to exit).
+        #[cfg_attr(any(test, doctest), allow(dead_code))]
+        pub(crate) fn unique_thread_exit() {
+            let this_thread_id = unsafe { libc::pthread_self() };
+            use crate::sync::{Mutex, PoisonError};
+            static EXITING_THREAD_ID: Mutex<Option<PThread>> = Mutex::new(None);
+            let mut exiting_thread_id =
+                EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner);
+            match *exiting_thread_id {
+                None => {
+                    // This is the first thread to call `unique_thread_exit`,
+                    // and this is the first time it is called.
+                    // Set EXITING_THREAD_ID to this thread's ID and return.
+                    *exiting_thread_id = Some(PThread(this_thread_id));
+                },
+                Some(exiting_thread_id) if exiting_thread_id.0 == this_thread_id => {
+                    // This is the first thread to call `unique_thread_exit`,
+                    // but this is the second time it is called.
+                    // Abort the process.
+                    core::panicking::panic_nounwind("std::process::exit called re-entrantly")
+                }
+                Some(_) => {
+                    // This is not the first thread to call `unique_thread_exit`.
+                    // Pause until the process exits.
+                    drop(exiting_thread_id);
+                    loop {
+                        // Safety: libc::pause is safe to call.
+                        unsafe { libc::pause(); }
+                    }
+                }
+            }
+        }
+    } else {
+        /// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
+        ///
+        /// Mitigation is ***NOT*** implemented on this platform, either because this platform
+        /// is not affected, or because mitigation is not yet implemented for this platform.
+        #[cfg_attr(any(test, doctest), allow(dead_code))]
+        pub(crate) fn unique_thread_exit() {
+            // Mitigation not required on platforms where `exit` is thread-safe.
+        }
+    }
+}
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 8aa35c40fe0..e50758ce00d 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -1,3 +1,5 @@
+#![allow(unsafe_op_in_unsafe_fn)]
+
 /// The PAL (platform abstraction layer) contains platform-specific abstractions
 /// for implementing the features in the other submodules, e.g. UNIX file
 /// descriptors.
@@ -7,6 +9,7 @@ mod personality;
 
 pub mod backtrace;
 pub mod cmath;
+pub mod exit_guard;
 pub mod os_str;
 pub mod path;
 pub mod sync;
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index 8c75ac65299..df017624448 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -94,36 +94,5 @@ cfg_if::cfg_if! {
     }
 }
 
-// Solaris/Illumos requires a wrapper around log, log2, and log10 functions
-// because of their non-standard behavior (e.g., log(-n) returns -Inf instead
-// of expected NaN).
-#[cfg(not(test))]
-#[cfg(any(target_os = "solaris", target_os = "illumos"))]
-#[inline]
-pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 {
-    if n.is_finite() {
-        if n > 0.0 {
-            log_fn(n)
-        } else if n == 0.0 {
-            f64::NEG_INFINITY // log(0) = -Inf
-        } else {
-            f64::NAN // log(-n) = NaN
-        }
-    } else if n.is_nan() {
-        n // log(NaN) = NaN
-    } else if n > 0.0 {
-        n // log(Inf) = Inf
-    } else {
-        f64::NAN // log(-Inf) = NaN
-    }
-}
-
-#[cfg(not(test))]
-#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
-#[inline]
-pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 {
-    log_fn(n)
-}
-
 #[cfg(not(target_os = "uefi"))]
 pub type RawOsError = i32;
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index f9d6b5fbc86..8308a48f16a 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -2010,56 +2010,10 @@ mod remove_dir_impl {
     use crate::sys::common::small_c_string::run_path_with_cstr;
     use crate::sys::{cvt, cvt_r};
 
-    #[cfg(not(any(
-        all(target_os = "linux", target_env = "gnu"),
-        all(target_os = "macos", not(target_arch = "aarch64"))
-    )))]
+    #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
     use libc::{fdopendir, openat, unlinkat};
     #[cfg(all(target_os = "linux", target_env = "gnu"))]
     use libc::{fdopendir, openat64 as openat, unlinkat};
-    #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))]
-    use macos_weak::{fdopendir, openat, unlinkat};
-
-    #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))]
-    mod macos_weak {
-        use crate::sys::weak::weak;
-        use libc::{c_char, c_int, DIR};
-
-        fn get_openat_fn() -> Option<unsafe extern "C" fn(c_int, *const c_char, c_int) -> c_int> {
-            weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
-            openat.get()
-        }
-
-        pub fn has_openat() -> bool {
-            get_openat_fn().is_some()
-        }
-
-        pub unsafe fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
-            get_openat_fn().map(|openat| openat(dirfd, pathname, flags)).unwrap_or_else(|| {
-                crate::sys::pal::unix::os::set_errno(libc::ENOSYS);
-                -1
-            })
-        }
-
-        pub unsafe fn fdopendir(fd: c_int) -> *mut DIR {
-            #[cfg(all(target_os = "macos", target_arch = "x86"))]
-            weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64$UNIX2003");
-            #[cfg(all(target_os = "macos", target_arch = "x86_64"))]
-            weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64");
-            fdopendir.get().map(|fdopendir| fdopendir(fd)).unwrap_or_else(|| {
-                crate::sys::pal::unix::os::set_errno(libc::ENOSYS);
-                crate::ptr::null_mut()
-            })
-        }
-
-        pub unsafe fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
-            weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int);
-            unlinkat.get().map(|unlinkat| unlinkat(dirfd, pathname, flags)).unwrap_or_else(|| {
-                crate::sys::pal::unix::os::set_errno(libc::ENOSYS);
-                -1
-            })
-        }
-    }
 
     pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
         let fd = cvt_r(|| unsafe {
@@ -2172,19 +2126,7 @@ mod remove_dir_impl {
         }
     }
 
-    #[cfg(not(all(target_os = "macos", not(target_arch = "aarch64"))))]
     pub fn remove_dir_all(p: &Path) -> io::Result<()> {
         remove_dir_all_modern(p)
     }
-
-    #[cfg(all(target_os = "macos", not(target_arch = "aarch64")))]
-    pub fn remove_dir_all(p: &Path) -> io::Result<()> {
-        if macos_weak::has_openat() {
-            // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir()
-            remove_dir_all_modern(p)
-        } else {
-            // fall back to classic implementation
-            crate::sys_common::fs::remove_dir_all(p)
-        }
-    }
 }
diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs
index 6d9532f2ef1..fb928c76fbd 100644
--- a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs
+++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs
@@ -1,7 +1,7 @@
 use crate::assert_matches::assert_matches;
 use crate::os::fd::{AsRawFd, RawFd};
-use crate::os::linux::process::{ChildExt, CommandExt};
-use crate::os::unix::process::ExitStatusExt;
+use crate::os::linux::process::{ChildExt, CommandExt as _};
+use crate::os::unix::process::{CommandExt as _, ExitStatusExt};
 use crate::process::Command;
 
 #[test]
@@ -21,6 +21,7 @@ fn test_command_pidfd() {
         let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap();
         assert!(flags & libc::FD_CLOEXEC != 0);
     }
+    assert!(child.id() > 0 && child.id() < -1i32 as u32);
     let status = child.wait().expect("error waiting on pidfd");
     assert_eq!(status.code(), Some(1));
 
@@ -42,6 +43,17 @@ fn test_command_pidfd() {
         .unwrap()
         .pidfd()
         .expect_err("pidfd should not have been created");
+
+    // exercise the fork/exec path since the earlier attempts may have used pidfd_spawnp()
+    let mut child =
+        unsafe { Command::new("false").pre_exec(|| Ok(())) }.create_pidfd(true).spawn().unwrap();
+
+    assert!(child.id() > 0 && child.id() < -1i32 as u32);
+
+    if pidfd_open_available {
+        assert!(child.pidfd().is_ok())
+    }
+    child.wait().expect("error waiting on child");
 }
 
 #[test]
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 16fc2011d70..262f9c704a8 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -305,10 +305,13 @@ macro_rules! impl_is_minus_one {
 
 impl_is_minus_one! { i8 i16 i32 i64 isize }
 
+/// Convert native return values to Result using the *-1 means error is in `errno`*  convention.
+/// Non-error values are `Ok`-wrapped.
 pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
     if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
 }
 
+/// `-1` → look at `errno` → retry on `EINTR`. Otherwise `Ok()`-wrap the closure return value.
 pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
 where
     T: IsMinusOne,
@@ -323,6 +326,7 @@ where
 }
 
 #[allow(dead_code)] // Not used on all platforms.
+/// Zero means `Ok()`, all other values are treated as raw OS errors. Does not look at `errno`.
 pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
     if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) }
 }
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 40e2d1403ef..9adc2b94e59 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -758,6 +758,7 @@ pub fn home_dir() -> Option<PathBuf> {
 }
 
 pub fn exit(code: i32) -> ! {
+    crate::sys::exit_guard::unique_thread_exit();
     unsafe { libc::exit(code as c_int) }
 }
 
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 32382d9a50c..abd4a334783 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -449,17 +449,82 @@ impl Command {
         use crate::mem::MaybeUninit;
         use crate::sys::weak::weak;
         use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
+        #[cfg(target_os = "linux")]
+        use core::sync::atomic::{AtomicU8, Ordering};
 
         if self.get_gid().is_some()
             || self.get_uid().is_some()
             || (self.env_saw_path() && !self.program_is_path())
             || !self.get_closures().is_empty()
             || self.get_groups().is_some()
-            || self.get_create_pidfd()
         {
             return Ok(None);
         }
 
+        cfg_if::cfg_if! {
+            if #[cfg(target_os = "linux")] {
+                weak! {
+                    fn pidfd_spawnp(
+                        *mut libc::c_int,
+                        *const libc::c_char,
+                        *const libc::posix_spawn_file_actions_t,
+                        *const libc::posix_spawnattr_t,
+                        *const *mut libc::c_char,
+                        *const *mut libc::c_char
+                    ) -> libc::c_int
+                }
+
+                weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int }
+
+                static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0);
+                const UNKNOWN: u8 = 0;
+                const SPAWN: u8 = 1;
+                // Obtaining a pidfd via the fork+exec path might work
+                const FORK_EXEC: u8 = 2;
+                // Neither pidfd_spawn nor fork/exec will get us a pidfd.
+                // Instead we'll just posix_spawn if the other preconditions are met.
+                const NO: u8 = 3;
+
+                if self.get_create_pidfd() {
+                    let mut support = PIDFD_SUPPORTED.load(Ordering::Relaxed);
+                    if support == FORK_EXEC {
+                        return Ok(None);
+                    }
+                    if support == UNKNOWN {
+                        support = NO;
+                        let our_pid = crate::process::id();
+                        let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as c_int);
+                        match pidfd {
+                            Ok(pidfd) => {
+                                support = FORK_EXEC;
+                                if let Some(Ok(pid)) = pidfd_getpid.get().map(|f| cvt(unsafe { f(pidfd) } as i32)) {
+                                    if pidfd_spawnp.get().is_some() && pid as u32 == our_pid {
+                                        support = SPAWN
+                                    }
+                                }
+                                unsafe { libc::close(pidfd) };
+                            }
+                            Err(e) if e.raw_os_error() == Some(libc::EMFILE) => {
+                                // We're temporarily(?) out of file descriptors.  In this case obtaining a pidfd would also fail
+                                // Don't update the support flag so we can probe again later.
+                                return Err(e)
+                            }
+                            _ => {}
+                        }
+                        PIDFD_SUPPORTED.store(support, Ordering::Relaxed);
+                        if support == FORK_EXEC {
+                            return Ok(None);
+                        }
+                    }
+                    core::assert_matches::debug_assert_matches!(support, SPAWN | NO);
+                }
+            } else {
+                if self.get_create_pidfd() {
+                    unreachable!("only implemented on linux")
+                }
+            }
+        }
+
         // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly.
         #[cfg(all(target_os = "linux", target_env = "gnu"))]
         {
@@ -543,9 +608,6 @@ impl Command {
 
         let pgroup = self.get_pgroup();
 
-        // Safety: -1 indicates we don't have a pidfd.
-        let mut p = unsafe { Process::new(0, -1) };
-
         struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);
 
         impl Drop for PosixSpawnFileActions<'_> {
@@ -640,6 +702,47 @@ impl Command {
             #[cfg(target_os = "nto")]
             let spawn_fn = retrying_libc_posix_spawnp;
 
+            #[cfg(target_os = "linux")]
+            if self.get_create_pidfd() && PIDFD_SUPPORTED.load(Ordering::Relaxed) == SPAWN {
+                let mut pidfd: libc::c_int = -1;
+                let spawn_res = pidfd_spawnp.get().unwrap()(
+                    &mut pidfd,
+                    self.get_program_cstr().as_ptr(),
+                    file_actions.0.as_ptr(),
+                    attrs.0.as_ptr(),
+                    self.get_argv().as_ptr() as *const _,
+                    envp as *const _,
+                );
+
+                let spawn_res = cvt_nz(spawn_res);
+                if let Err(ref e) = spawn_res
+                    && e.raw_os_error() == Some(libc::ENOSYS)
+                {
+                    PIDFD_SUPPORTED.store(FORK_EXEC, Ordering::Relaxed);
+                    return Ok(None);
+                }
+                spawn_res?;
+
+                let pid = match cvt(pidfd_getpid.get().unwrap()(pidfd)) {
+                    Ok(pid) => pid,
+                    Err(e) => {
+                        // The child has been spawned and we are holding its pidfd.
+                        // But we cannot obtain its pid even though pidfd_getpid support was verified earlier.
+                        // This might happen if libc can't open procfs because the file descriptor limit has been reached.
+                        libc::close(pidfd);
+                        return Err(Error::new(
+                            e.kind(),
+                            "pidfd_spawnp succeeded but the child's PID could not be obtained",
+                        ));
+                    }
+                };
+
+                return Ok(Some(Process::new(pid, pidfd)));
+            }
+
+            // Safety: -1 indicates we don't have a pidfd.
+            let mut p = Process::new(0, -1);
+
             let spawn_res = spawn_fn(
                 &mut p.pid,
                 self.get_program_cstr().as_ptr(),
@@ -786,6 +889,12 @@ pub struct Process {
 
 impl Process {
     #[cfg(target_os = "linux")]
+    /// # Safety
+    ///
+    /// `pidfd` must either be -1 (representing no file descriptor) or a valid, exclusively owned file
+    /// descriptor (See [I/O Safety]).
+    ///
+    /// [I/O Safety]: crate::io#io-safety
     unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self {
         use crate::os::unix::io::FromRawFd;
         use crate::sys_common::FromInner;
diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs
index 24c237b5eb0..9f0194492b0 100644
--- a/library/std/src/sys/pal/windows/alloc.rs
+++ b/library/std/src/sys/pal/windows/alloc.rs
@@ -4,7 +4,7 @@ use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ffi::c_void;
 use crate::ptr;
 use crate::sync::atomic::{AtomicPtr, Ordering};
-use crate::sys::c;
+use crate::sys::c::{self, windows_targets};
 use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
 use core::mem::MaybeUninit;
 
@@ -15,76 +15,73 @@ mod tests;
 // See https://docs.microsoft.com/windows/win32/api/heapapi/
 
 // Flag to indicate that the memory returned by `HeapAlloc` should be zeroed.
-const HEAP_ZERO_MEMORY: c::DWORD = 0x00000008;
+const HEAP_ZERO_MEMORY: u32 = 0x00000008;
 
-#[link(name = "kernel32")]
-extern "system" {
-    // Get a handle to the default heap of the current process, or null if the operation fails.
-    //
-    // SAFETY: Successful calls to this function within the same process are assumed to
-    // always return the same handle, which remains valid for the entire lifetime of the process.
-    //
-    // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap
-    fn GetProcessHeap() -> c::HANDLE;
+// Get a handle to the default heap of the current process, or null if the operation fails.
+//
+// SAFETY: Successful calls to this function within the same process are assumed to
+// always return the same handle, which remains valid for the entire lifetime of the process.
+//
+// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap
+windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE);
 
-    // Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`.
-    // The allocated memory may be uninitialized, or zeroed if `dwFlags` is
-    // set to `HEAP_ZERO_MEMORY`.
-    //
-    // Returns a pointer to the newly-allocated memory or null if the operation fails.
-    // The returned pointer will be aligned to at least `MIN_ALIGN`.
-    //
-    // SAFETY:
-    //  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
-    //  - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`.
-    //
-    // Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
-    //
-    // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc
-    fn HeapAlloc(hHeap: c::HANDLE, dwFlags: c::DWORD, dwBytes: c::SIZE_T) -> c::LPVOID;
+// Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`.
+// The allocated memory may be uninitialized, or zeroed if `dwFlags` is
+// set to `HEAP_ZERO_MEMORY`.
+//
+// Returns a pointer to the newly-allocated memory or null if the operation fails.
+// The returned pointer will be aligned to at least `MIN_ALIGN`.
+//
+// SAFETY:
+//  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
+//  - `dwFlags` must be set to either zero or `HEAP_ZERO_MEMORY`.
+//
+// Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
+//
+// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc
+windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut core::ffi::c_void);
 
-    // Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`,
-    // to a block of at least `dwBytes` bytes, either shrinking the block in place,
-    // or allocating at a new location, copying memory, and freeing the original location.
-    //
-    // Returns a pointer to the reallocated memory or null if the operation fails.
-    // The returned pointer will be aligned to at least `MIN_ALIGN`.
-    // If the operation fails the given block will never have been freed.
-    //
-    // SAFETY:
-    //  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
-    //  - `dwFlags` must be set to zero.
-    //  - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or
-    //     `HeapReAlloc`, that has not already been freed.
-    // If the block was successfully reallocated at a new location, pointers pointing to
-    // the freed memory, such as `lpMem`, must not be dereferenced ever again.
-    //
-    // Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
-    //
-    // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc
-    fn HeapReAlloc(
-        hHeap: c::HANDLE,
-        dwFlags: c::DWORD,
-        lpMem: c::LPVOID,
-        dwBytes: c::SIZE_T,
-    ) -> c::LPVOID;
+// Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`,
+// to a block of at least `dwBytes` bytes, either shrinking the block in place,
+// or allocating at a new location, copying memory, and freeing the original location.
+//
+// Returns a pointer to the reallocated memory or null if the operation fails.
+// The returned pointer will be aligned to at least `MIN_ALIGN`.
+// If the operation fails the given block will never have been freed.
+//
+// SAFETY:
+//  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
+//  - `dwFlags` must be set to zero.
+//  - `lpMem` must be a non-null pointer to an allocated block returned by `HeapAlloc` or
+//     `HeapReAlloc`, that has not already been freed.
+// If the block was successfully reallocated at a new location, pointers pointing to
+// the freed memory, such as `lpMem`, must not be dereferenced ever again.
+//
+// Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
+//
+// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc
+windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
+    hheap: c::HANDLE,
+    dwflags : u32,
+    lpmem: *const core::ffi::c_void,
+    dwbytes: usize
+) -> *mut core::ffi::c_void);
 
-    // Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`.
-    // Returns a nonzero value if the operation is successful, and zero if the operation fails.
-    //
-    // SAFETY:
-    //  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
-    //  - `dwFlags` must be set to zero.
-    //  - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`,
-    //     that has not already been freed.
-    // If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`,
-    // must not be dereferenced ever again.
-    //
-    // Note that `lpMem` is allowed to be null, which will not cause the operation to fail.
-    //
-    // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree
-    fn HeapFree(hHeap: c::HANDLE, dwFlags: c::DWORD, lpMem: c::LPVOID) -> c::BOOL;
-}
+// Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`.
+// Returns a nonzero value if the operation is successful, and zero if the operation fails.
+//
+// SAFETY:
+//  - `hHeap` must be a non-null handle returned by `GetProcessHeap`.
+//  - `dwFlags` must be set to zero.
+//  - `lpMem` must be a pointer to an allocated block returned by `HeapAlloc` or `HeapReAlloc`,
+//     that has not already been freed.
+// If the block was successfully freed, pointers pointing to the freed memory, such as `lpMem`,
+// must not be dereferenced ever again.
+//
+// Note that `lpMem` is allowed to be null, which will not cause the operation to fail.
+//
+// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree
+windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const core::ffi::c_void) -> c::BOOL);
 
 // Cached handle to the default heap of the current process.
 // Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed.
@@ -116,9 +113,9 @@ fn init_or_get_process_heap() -> c::HANDLE {
 #[cold]
 extern "C" fn process_heap_init_and_alloc(
     _heap: MaybeUninit<c::HANDLE>, // We pass this argument to match the ABI of `HeapAlloc`
-    flags: c::DWORD,
-    dwBytes: c::SIZE_T,
-) -> c::LPVOID {
+    flags: u32,
+    dwBytes: usize,
+) -> *mut c_void {
     let heap = init_or_get_process_heap();
     if core::intrinsics::unlikely(heap.is_null()) {
         return ptr::null_mut();
@@ -130,9 +127,9 @@ extern "C" fn process_heap_init_and_alloc(
 #[inline(never)]
 fn process_heap_alloc(
     _heap: MaybeUninit<c::HANDLE>, // We pass this argument to match the ABI of `HeapAlloc`,
-    flags: c::DWORD,
-    dwBytes: c::SIZE_T,
-) -> c::LPVOID {
+    flags: u32,
+    dwBytes: usize,
+) -> *mut c_void {
     let heap = HEAP.load(Ordering::Relaxed);
     if core::intrinsics::likely(!heap.is_null()) {
         // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`.
@@ -243,7 +240,7 @@ unsafe impl GlobalAlloc for System {
 
         // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`,
         // `block` is a pointer to the start of an allocated block.
-        unsafe { HeapFree(heap, 0, block as c::LPVOID) };
+        unsafe { HeapFree(heap, 0, block.cast::<c_void>()) };
     }
 
     #[inline]
@@ -256,7 +253,7 @@ unsafe impl GlobalAlloc for System {
             // SAFETY: `heap` is a non-null handle returned by `GetProcessHeap`,
             // `ptr` is a pointer to the start of an allocated block.
             // The returned pointer points to the start of an allocated block.
-            unsafe { HeapReAlloc(heap, 0, ptr as c::LPVOID, new_size) as *mut u8 }
+            unsafe { HeapReAlloc(heap, 0, ptr.cast::<c_void>(), new_size).cast::<u8>() }
         } else {
             // SAFETY: `realloc_fallback` is implemented using `dealloc` and `alloc`, which will
             // correctly handle `ptr` and return a pointer satisfying the guarantees of `System`
diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs
index 17a0e47ad59..00c816a6c09 100644
--- a/library/std/src/sys/pal/windows/api.rs
+++ b/library/std/src/sys/pal/windows/api.rs
@@ -227,8 +227,10 @@ pub fn set_file_information_by_handle<T: SetFileInformation>(
         info: *const c_void,
         size: u32,
     ) -> Result<(), WinError> {
-        let result = c::SetFileInformationByHandle(handle, class, info, size);
-        (result != 0).then_some(()).ok_or_else(get_last_error)
+        unsafe {
+            let result = c::SetFileInformationByHandle(handle, class, info, size);
+            (result != 0).then_some(()).ok_or_else(get_last_error)
+        }
     }
     // SAFETY: The `SetFileInformation` trait ensures that this is safe.
     unsafe { set_info(handle, T::CLASS, info.as_ptr(), info.size()) }
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 27aa35f69f1..296d19a926d 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -4,44 +4,23 @@
 #![cfg_attr(test, allow(dead_code))]
 #![unstable(issue = "none", feature = "windows_c")]
 #![allow(clippy::style)]
+#![allow(unsafe_op_in_unsafe_fn)]
 
 use crate::ffi::CStr;
 use crate::mem;
-use crate::num::NonZero;
-pub use crate::os::raw::c_int;
-use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_void};
+use crate::os::raw::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void};
 use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
 use crate::ptr;
 
-mod windows_targets;
+pub(super) mod windows_targets;
 
 mod windows_sys;
 pub use windows_sys::*;
 
-pub type DWORD = c_ulong;
-pub type NonZeroDWORD = NonZero<c_ulong>;
-pub type LARGE_INTEGER = c_longlong;
-#[cfg_attr(target_vendor = "uwp", allow(unused))]
-pub type LONG = c_long;
-pub type UINT = c_uint;
 pub type WCHAR = u16;
-pub type USHORT = c_ushort;
-pub type SIZE_T = usize;
-pub type CHAR = c_char;
-pub type ULONG = c_ulong;
-
-pub type LPCVOID = *const c_void;
-pub type LPOVERLAPPED = *mut OVERLAPPED;
-pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
-pub type LPVOID = *mut c_void;
-pub type LPWCH = *mut WCHAR;
-pub type LPWSTR = *mut WCHAR;
-
-#[cfg(target_vendor = "win7")]
-pub type PSRWLOCK = *mut SRWLOCK;
 
 pub type socklen_t = c_int;
-pub type ADDRESS_FAMILY = USHORT;
+pub type ADDRESS_FAMILY = c_ushort;
 pub use FD_SET as fd_set;
 pub use LINGER as linger;
 pub use TIMEVAL as timeval;
@@ -151,25 +130,25 @@ pub struct MOUNT_POINT_REPARSE_BUFFER {
 #[repr(C)]
 pub struct SOCKADDR_STORAGE_LH {
     pub ss_family: ADDRESS_FAMILY,
-    pub __ss_pad1: [CHAR; 6],
+    pub __ss_pad1: [c_char; 6],
     pub __ss_align: i64,
-    pub __ss_pad2: [CHAR; 112],
+    pub __ss_pad2: [c_char; 112],
 }
 
 #[repr(C)]
 #[derive(Copy, Clone)]
 pub struct sockaddr_in {
     pub sin_family: ADDRESS_FAMILY,
-    pub sin_port: USHORT,
+    pub sin_port: c_ushort,
     pub sin_addr: in_addr,
-    pub sin_zero: [CHAR; 8],
+    pub sin_zero: [c_char; 8],
 }
 
 #[repr(C)]
 #[derive(Copy, Clone)]
 pub struct sockaddr_in6 {
     pub sin6_family: ADDRESS_FAMILY,
-    pub sin6_port: USHORT,
+    pub sin6_port: c_ushort,
     pub sin6_flowinfo: c_ulong,
     pub sin6_addr: in6_addr,
     pub sin6_scope_id: c_ulong,
@@ -271,9 +250,9 @@ pub unsafe fn NtReadFile(
     apccontext: *mut c_void,
     iostatusblock: &mut IO_STATUS_BLOCK,
     buffer: *mut crate::mem::MaybeUninit<u8>,
-    length: ULONG,
-    byteoffset: Option<&LARGE_INTEGER>,
-    key: Option<&ULONG>,
+    length: u32,
+    byteoffset: Option<&i64>,
+    key: Option<&u32>,
 ) -> NTSTATUS {
     windows_sys::NtReadFile(
         filehandle.as_raw_handle(),
@@ -294,9 +273,9 @@ pub unsafe fn NtWriteFile(
     apccontext: *mut c_void,
     iostatusblock: &mut IO_STATUS_BLOCK,
     buffer: *const u8,
-    length: ULONG,
-    byteoffset: Option<&LARGE_INTEGER>,
-    key: Option<&ULONG>,
+    length: u32,
+    byteoffset: Option<&i64>,
+    key: Option<&u32>,
 ) -> NTSTATUS {
     windows_sys::NtWriteFile(
         filehandle.as_raw_handle(),
@@ -336,13 +315,13 @@ compat_fn_with_fallback! {
     // >= Win10 1607
     // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
     pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT {
-        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL
     }
 
     // >= Win10 1607
     // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription
     pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT {
-        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL
     }
 
     // >= Win8 / Server 2012
@@ -403,27 +382,27 @@ compat_fn_with_fallback! {
     #[cfg(target_vendor = "win7")]
     pub fn NtCreateKeyedEvent(
         KeyedEventHandle: *mut HANDLE,
-        DesiredAccess: DWORD,
-        ObjectAttributes: LPVOID,
-        Flags: ULONG
+        DesiredAccess: u32,
+        ObjectAttributes: *mut c_void,
+        Flags: u32
     ) -> NTSTATUS {
         panic!("keyed events not available")
     }
     #[cfg(target_vendor = "win7")]
     pub fn NtReleaseKeyedEvent(
         EventHandle: HANDLE,
-        Key: LPVOID,
+        Key: *const c_void,
         Alertable: BOOLEAN,
-        Timeout: *mut c_longlong
+        Timeout: *mut i64
     ) -> NTSTATUS {
         panic!("keyed events not available")
     }
     #[cfg(target_vendor = "win7")]
     pub fn NtWaitForKeyedEvent(
         EventHandle: HANDLE,
-        Key: LPVOID,
+        Key: *const c_void,
         Alertable: BOOLEAN,
-        Timeout: *mut c_longlong
+        Timeout: *mut i64
     ) -> NTSTATUS {
         panic!("keyed events not available")
     }
@@ -453,9 +432,9 @@ compat_fn_with_fallback! {
         apccontext: *mut c_void,
         iostatusblock: &mut IO_STATUS_BLOCK,
         buffer: *mut crate::mem::MaybeUninit<u8>,
-        length: ULONG,
-        byteoffset: Option<&LARGE_INTEGER>,
-        key: Option<&ULONG>
+        length: u32,
+        byteoffset: Option<&i64>,
+        key: Option<&u32>
     ) -> NTSTATUS {
         STATUS_NOT_IMPLEMENTED
     }
@@ -467,9 +446,9 @@ compat_fn_with_fallback! {
         apccontext: *mut c_void,
         iostatusblock: &mut IO_STATUS_BLOCK,
         buffer: *const u8,
-        length: ULONG,
-        byteoffset: Option<&LARGE_INTEGER>,
-        key: Option<&ULONG>
+        length: u32,
+        byteoffset: Option<&i64>,
+        key: Option<&u32>
     ) -> NTSTATUS {
         STATUS_NOT_IMPLEMENTED
     }
diff --git a/library/std/src/sys/pal/windows/c/windows_targets.rs b/library/std/src/sys/pal/windows/c/windows_targets.rs
index 56c563462d3..252bceb7094 100644
--- a/library/std/src/sys/pal/windows/c/windows_targets.rs
+++ b/library/std/src/sys/pal/windows/c/windows_targets.rs
@@ -3,6 +3,18 @@
 //! This is a simple wrapper around an `extern` block with a `#[link]` attribute.
 //! It's very roughly equivalent to the windows-targets crate.
 
+#[cfg(feature = "windows_raw_dylib")]
+pub macro link {
+    ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
+        #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))]
+        #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))]
+        extern $abi {
+            $(#[link_name=$link_name])?
+            pub fn $($function)*;
+        }
+    )
+}
+#[cfg(not(feature = "windows_raw_dylib"))]
 pub macro link {
     ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
         // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't
@@ -17,6 +29,7 @@ pub macro link {
     )
 }
 
+#[cfg(not(feature = "windows_raw_dylib"))]
 #[link(name = "advapi32")]
 #[link(name = "ntdll")]
 #[link(name = "userenv")]
diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs
index f5d57a28db6..49fa1603f3e 100644
--- a/library/std/src/sys/pal/windows/compat.rs
+++ b/library/std/src/sys/pal/windows/compat.rs
@@ -112,8 +112,10 @@ impl Module {
     /// (e.g. kernel32 and ntdll).
     pub unsafe fn new(name: &CStr) -> Option<Self> {
         // SAFETY: A CStr is always null terminated.
-        let module = c::GetModuleHandleA(name.as_ptr().cast::<u8>());
-        NonNull::new(module).map(Self)
+        unsafe {
+            let module = c::GetModuleHandleA(name.as_ptr().cast::<u8>());
+            NonNull::new(module).map(Self)
+        }
     }
 
     // Try to get the address of a function.
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index cc68f5ef5f0..85fd9153d53 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -1,3 +1,4 @@
+#![allow(unsafe_op_in_unsafe_fn)]
 use core::ptr::addr_of;
 
 use crate::os::windows::prelude::*;
@@ -28,12 +29,12 @@ pub struct File {
 
 #[derive(Clone)]
 pub struct FileAttr {
-    attributes: c::DWORD,
+    attributes: u32,
     creation_time: c::FILETIME,
     last_access_time: c::FILETIME,
     last_write_time: c::FILETIME,
     file_size: u64,
-    reparse_tag: c::DWORD,
+    reparse_tag: u32,
     volume_serial_number: Option<u32>,
     number_of_links: Option<u32>,
     file_index: Option<u64>,
@@ -41,8 +42,8 @@ pub struct FileAttr {
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct FileType {
-    attributes: c::DWORD,
-    reparse_tag: c::DWORD,
+    attributes: u32,
+    reparse_tag: u32,
 }
 
 pub struct ReadDir {
@@ -75,16 +76,16 @@ pub struct OpenOptions {
     create_new: bool,
     // system-specific
     custom_flags: u32,
-    access_mode: Option<c::DWORD>,
-    attributes: c::DWORD,
-    share_mode: c::DWORD,
-    security_qos_flags: c::DWORD,
-    security_attributes: c::LPSECURITY_ATTRIBUTES,
+    access_mode: Option<u32>,
+    attributes: u32,
+    share_mode: u32,
+    security_qos_flags: u32,
+    security_attributes: *mut c::SECURITY_ATTRIBUTES,
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct FilePermissions {
-    attrs: c::DWORD,
+    attrs: u32,
 }
 
 #[derive(Copy, Clone, Debug, Default)]
@@ -241,11 +242,11 @@ impl OpenOptions {
         // receive is `SECURITY_ANONYMOUS = 0x0`, which we can't check for later on.
         self.security_qos_flags = flags | c::SECURITY_SQOS_PRESENT;
     }
-    pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) {
+    pub fn security_attributes(&mut self, attrs: *mut c::SECURITY_ATTRIBUTES) {
         self.security_attributes = attrs;
     }
 
-    fn get_access_mode(&self) -> io::Result<c::DWORD> {
+    fn get_access_mode(&self) -> io::Result<u32> {
         match (self.read, self.write, self.append, self.access_mode) {
             (.., Some(mode)) => Ok(mode),
             (true, false, false, None) => Ok(c::GENERIC_READ),
@@ -261,7 +262,7 @@ impl OpenOptions {
         }
     }
 
-    fn get_creation_mode(&self) -> io::Result<c::DWORD> {
+    fn get_creation_mode(&self) -> io::Result<u32> {
         match (self.write, self.append) {
             (true, false) => {}
             (false, false) => {
@@ -287,7 +288,7 @@ impl OpenOptions {
         })
     }
 
-    fn get_flags_and_attributes(&self) -> c::DWORD {
+    fn get_flags_and_attributes(&self) -> u32 {
         self.custom_flags
             | self.attributes
             | self.security_qos_flags
@@ -397,21 +398,21 @@ impl File {
                 self.handle.as_raw_handle(),
                 c::FileBasicInfo,
                 core::ptr::addr_of_mut!(info) as *mut c_void,
-                size as c::DWORD,
+                size as u32,
             ))?;
             let mut attr = FileAttr {
                 attributes: info.FileAttributes,
                 creation_time: c::FILETIME {
-                    dwLowDateTime: info.CreationTime as c::DWORD,
-                    dwHighDateTime: (info.CreationTime >> 32) as c::DWORD,
+                    dwLowDateTime: info.CreationTime as u32,
+                    dwHighDateTime: (info.CreationTime >> 32) as u32,
                 },
                 last_access_time: c::FILETIME {
-                    dwLowDateTime: info.LastAccessTime as c::DWORD,
-                    dwHighDateTime: (info.LastAccessTime >> 32) as c::DWORD,
+                    dwLowDateTime: info.LastAccessTime as u32,
+                    dwHighDateTime: (info.LastAccessTime >> 32) as u32,
                 },
                 last_write_time: c::FILETIME {
-                    dwLowDateTime: info.LastWriteTime as c::DWORD,
-                    dwHighDateTime: (info.LastWriteTime >> 32) as c::DWORD,
+                    dwLowDateTime: info.LastWriteTime as u32,
+                    dwHighDateTime: (info.LastWriteTime >> 32) as u32,
                 },
                 file_size: 0,
                 reparse_tag: 0,
@@ -425,7 +426,7 @@ impl File {
                 self.handle.as_raw_handle(),
                 c::FileStandardInfo,
                 core::ptr::addr_of_mut!(info) as *mut c_void,
-                size as c::DWORD,
+                size as u32,
             ))?;
             attr.file_size = info.AllocationSize as u64;
             attr.number_of_links = Some(info.NumberOfLinks);
@@ -495,7 +496,7 @@ impl File {
             SeekFrom::End(n) => (c::FILE_END, n),
             SeekFrom::Current(n) => (c::FILE_CURRENT, n),
         };
-        let pos = pos as c::LARGE_INTEGER;
+        let pos = pos as i64;
         let mut newpos = 0;
         cvt(unsafe { c::SetFilePointerEx(self.handle.as_raw_handle(), pos, &mut newpos, whence) })?;
         Ok(newpos as u64)
@@ -511,7 +512,7 @@ impl File {
     fn reparse_point(
         &self,
         space: &mut Align8<[MaybeUninit<u8>]>,
-    ) -> io::Result<(c::DWORD, *mut c::REPARSE_DATA_BUFFER)> {
+    ) -> io::Result<(u32, *mut c::REPARSE_DATA_BUFFER)> {
         unsafe {
             let mut bytes = 0;
             cvt({
@@ -524,7 +525,7 @@ impl File {
                     ptr::null_mut(),
                     0,
                     space.0.as_mut_ptr().cast(),
-                    len as c::DWORD,
+                    len as u32,
                     &mut bytes,
                     ptr::null_mut(),
                 )
@@ -609,8 +610,7 @@ impl File {
                 "Cannot set file timestamp to 0",
             ));
         }
-        let is_max =
-            |t: c::FILETIME| t.dwLowDateTime == c::DWORD::MAX && t.dwHighDateTime == c::DWORD::MAX;
+        let is_max = |t: c::FILETIME| t.dwLowDateTime == u32::MAX && t.dwHighDateTime == u32::MAX;
         if times.accessed.map_or(false, is_max)
             || times.modified.map_or(false, is_max)
             || times.created.map_or(false, is_max)
@@ -641,7 +641,7 @@ impl File {
                 self.handle.as_raw_handle(),
                 c::FileBasicInfo,
                 core::ptr::addr_of_mut!(info) as *mut c_void,
-                size as c::DWORD,
+                size as u32,
             ))?;
             Ok(info)
         }
@@ -1020,7 +1020,7 @@ impl FileTimes {
 }
 
 impl FileType {
-    fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
+    fn new(attrs: u32, reparse_tag: u32) -> FileType {
         FileType { attributes: attrs, reparse_tag }
     }
     pub fn is_dir(&self) -> bool {
@@ -1417,16 +1417,16 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
 
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     unsafe extern "system" fn callback(
-        _TotalFileSize: c::LARGE_INTEGER,
-        _TotalBytesTransferred: c::LARGE_INTEGER,
-        _StreamSize: c::LARGE_INTEGER,
-        StreamBytesTransferred: c::LARGE_INTEGER,
-        dwStreamNumber: c::DWORD,
-        _dwCallbackReason: c::DWORD,
+        _TotalFileSize: i64,
+        _TotalBytesTransferred: i64,
+        _StreamSize: i64,
+        StreamBytesTransferred: i64,
+        dwStreamNumber: u32,
+        _dwCallbackReason: u32,
         _hSourceFile: c::HANDLE,
         _hDestinationFile: c::HANDLE,
-        lpData: c::LPCVOID,
-    ) -> c::DWORD {
+        lpData: *const c_void,
+    ) -> u32 {
         if dwStreamNumber == 1 {
             *(lpData as *mut i64) = StreamBytesTransferred;
         }
diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs
index 3f85bb0a099..ae9ea8ff584 100644
--- a/library/std/src/sys/pal/windows/handle.rs
+++ b/library/std/src/sys/pal/windows/handle.rs
@@ -1,4 +1,5 @@
 #![unstable(issue = "none", feature = "windows_handle")]
+#![allow(unsafe_op_in_unsafe_fn)]
 
 #[cfg(test)]
 mod tests;
@@ -141,7 +142,7 @@ impl Handle {
         buf: &mut [u8],
         overlapped: *mut c::OVERLAPPED,
     ) -> io::Result<Option<usize>> {
-        let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
+        let len = cmp::min(buf.len(), u32::MAX as usize) as u32;
         let mut amt = 0;
         let res =
             cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped));
@@ -209,12 +210,7 @@ impl Handle {
         Ok(Self(self.0.try_clone()?))
     }
 
-    pub fn duplicate(
-        &self,
-        access: c::DWORD,
-        inherit: bool,
-        options: c::DWORD,
-    ) -> io::Result<Self> {
+    pub fn duplicate(&self, access: u32, inherit: bool, options: u32) -> io::Result<Self> {
         Ok(Self(self.0.as_handle().duplicate(access, inherit, options)?))
     }
 
@@ -233,7 +229,7 @@ impl Handle {
         let mut io_status = c::IO_STATUS_BLOCK::PENDING;
 
         // The length is clamped at u32::MAX.
-        let len = cmp::min(len, c::DWORD::MAX as usize) as c::DWORD;
+        let len = cmp::min(len, u32::MAX as usize) as u32;
         let status = c::NtReadFile(
             self.as_handle(),
             ptr::null_mut(),
@@ -281,7 +277,7 @@ impl Handle {
         let mut io_status = c::IO_STATUS_BLOCK::PENDING;
 
         // The length is clamped at u32::MAX.
-        let len = cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
+        let len = cmp::min(buf.len(), u32::MAX as usize) as u32;
         let status = unsafe {
             c::NtWriteFile(
                 self.as_handle(),
diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs
index 77b8f3c410e..86d457db50a 100644
--- a/library/std/src/sys/pal/windows/io.rs
+++ b/library/std/src/sys/pal/windows/io.rs
@@ -1,3 +1,4 @@
+#![allow(unsafe_op_in_unsafe_fn)]
 use crate::marker::PhantomData;
 use crate::mem::size_of;
 use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
@@ -15,9 +16,9 @@ pub struct IoSlice<'a> {
 impl<'a> IoSlice<'a> {
     #[inline]
     pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
-        assert!(buf.len() <= c::ULONG::MAX as usize);
+        assert!(buf.len() <= u32::MAX as usize);
         IoSlice {
-            vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_ptr() as *mut u8 },
+            vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 },
             _p: PhantomData,
         }
     }
@@ -29,7 +30,7 @@ impl<'a> IoSlice<'a> {
         }
 
         unsafe {
-            self.vec.len -= n as c::ULONG;
+            self.vec.len -= n as u32;
             self.vec.buf = self.vec.buf.add(n);
         }
     }
@@ -49,9 +50,9 @@ pub struct IoSliceMut<'a> {
 impl<'a> IoSliceMut<'a> {
     #[inline]
     pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
-        assert!(buf.len() <= c::ULONG::MAX as usize);
+        assert!(buf.len() <= u32::MAX as usize);
         IoSliceMut {
-            vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_mut_ptr() },
+            vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() },
             _p: PhantomData,
         }
     }
@@ -63,7 +64,7 @@ impl<'a> IoSliceMut<'a> {
         }
 
         unsafe {
-            self.vec.len -= n as c::ULONG;
+            self.vec.len -= n as u32;
             self.vec.buf = self.vec.buf.add(n);
         }
     }
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 6406cec9c27..b85a8318bcb 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -1,4 +1,5 @@
 #![allow(missing_docs, nonstandard_style)]
+#![deny(unsafe_op_in_unsafe_fn)]
 
 use crate::ffi::{OsStr, OsString};
 use crate::io::ErrorKind;
@@ -54,11 +55,13 @@ impl<T> IoResult<T> for Result<T, api::WinError> {
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
 pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
-    stack_overflow::init();
+    unsafe {
+        stack_overflow::init();
 
-    // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
-    // exists, we have to call it ourselves.
-    thread::Thread::set_name_wide(wide_str!("main"));
+        // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
+        // exists, we have to call it ourselves.
+        thread::Thread::set_name_wide(wide_str!("main"));
+    }
 }
 
 // SAFETY: must be called only once during runtime cleanup.
@@ -75,7 +78,7 @@ pub fn is_interrupted(_errno: i32) -> bool {
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
     use ErrorKind::*;
 
-    match errno as c::DWORD {
+    match errno as u32 {
         c::ERROR_ACCESS_DENIED => return PermissionDenied,
         c::ERROR_ALREADY_EXISTS => return AlreadyExists,
         c::ERROR_FILE_EXISTS => return AlreadyExists,
@@ -216,7 +219,7 @@ pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
 // from this closure is then the return value of the function.
 pub fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
 where
-    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
+    F1: FnMut(*mut u16, u32) -> u32,
     F2: FnOnce(&[u16]) -> T,
 {
     // Start off with a stack buf but then spill over to the heap if we end up
@@ -238,7 +241,7 @@ where
                 // We used `reserve` and not `reserve_exact`, so in theory we
                 // may have gotten more than requested. If so, we'd like to use
                 // it... so long as we won't cause overflow.
-                n = heap_buf.capacity().min(c::DWORD::MAX as usize);
+                n = heap_buf.capacity().min(u32::MAX as usize);
                 // Safety: MaybeUninit<u16> does not need initialization
                 heap_buf.set_len(n);
                 &mut heap_buf[..]
@@ -254,13 +257,13 @@ where
             // error" is still 0 then we interpret it as a 0 length buffer and
             // not an actual error.
             c::SetLastError(0);
-            let k = match f1(buf.as_mut_ptr().cast::<u16>(), n as c::DWORD) {
+            let k = match f1(buf.as_mut_ptr().cast::<u16>(), n as u32) {
                 0 if api::get_last_error().code == 0 => 0,
                 0 => return Err(crate::io::Error::last_os_error()),
                 n => n,
             } as usize;
             if k == n && api::get_last_error().code == c::ERROR_INSUFFICIENT_BUFFER {
-                n = n.saturating_mul(2).min(c::DWORD::MAX as usize);
+                n = n.saturating_mul(2).min(u32::MAX as usize);
             } else if k > n {
                 n = k;
             } else if k == n {
@@ -308,7 +311,7 @@ pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
     if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
 }
 
-pub fn dur2timeout(dur: Duration) -> c::DWORD {
+pub fn dur2timeout(dur: Duration) -> u32 {
     // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
     // timeouts in windows APIs are typically u32 milliseconds. To translate, we
     // have two pieces to take care of:
@@ -320,7 +323,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
         .checked_mul(1000)
         .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
         .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
-        .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD })
+        .map(|ms| if ms > <u32>::MAX as u64 { c::INFINITE } else { ms as u32 })
         .unwrap_or(c::INFINITE)
 }
 
diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs
index 9e15b15a351..d51fb56238f 100644
--- a/library/std/src/sys/pal/windows/net.rs
+++ b/library/std/src/sys/pal/windows/net.rs
@@ -250,7 +250,7 @@ impl Socket {
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
+        let length = cmp::min(bufs.len(), u32::MAX as usize) as u32;
         let mut nread = 0;
         let mut flags = 0;
         let result = unsafe {
@@ -335,7 +335,7 @@ impl Socket {
     }
 
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
+        let length = cmp::min(bufs.len(), u32::MAX as usize) as u32;
         let mut nwritten = 0;
         let result = unsafe {
             c::WSASend(
@@ -371,7 +371,7 @@ impl Socket {
     }
 
     pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
-        let raw: c::DWORD = net::getsockopt(self, c::SOL_SOCKET, kind)?;
+        let raw: u32 = net::getsockopt(self, c::SOL_SOCKET, kind)?;
         if raw == 0 {
             Ok(None)
         } else {
@@ -436,7 +436,7 @@ impl Socket {
     pub unsafe fn from_raw(raw: c::SOCKET) -> Self {
         debug_assert_eq!(mem::size_of::<c::SOCKET>(), mem::size_of::<RawSocket>());
         debug_assert_eq!(mem::align_of::<c::SOCKET>(), mem::align_of::<RawSocket>());
-        Self::from_raw_socket(raw as RawSocket)
+        unsafe { Self::from_raw_socket(raw as RawSocket) }
     }
 }
 
@@ -486,6 +486,6 @@ impl IntoRawSocket for Socket {
 
 impl FromRawSocket for Socket {
     unsafe fn from_raw_socket(raw_socket: RawSocket) -> Self {
-        Self(FromRawSocket::from_raw_socket(raw_socket))
+        unsafe { Self(FromRawSocket::from_raw_socket(raw_socket)) }
     }
 }
diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs
index 62199c16bfe..0a9279e50ba 100644
--- a/library/std/src/sys/pal/windows/os.rs
+++ b/library/std/src/sys/pal/windows/os.rs
@@ -1,6 +1,7 @@
 //! Implementation of `std::os` functionality for Windows.
 
 #![allow(nonstandard_style)]
+#![allow(unsafe_op_in_unsafe_fn)]
 
 #[cfg(test)]
 mod tests;
@@ -52,10 +53,10 @@ pub fn error_string(mut errnum: i32) -> String {
         let res = c::FormatMessageW(
             flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS,
             module,
-            errnum as c::DWORD,
+            errnum as u32,
             0,
             buf.as_mut_ptr(),
-            buf.len() as c::DWORD,
+            buf.len() as u32,
             ptr::null(),
         ) as usize;
         if res == 0 {
@@ -81,7 +82,7 @@ pub fn error_string(mut errnum: i32) -> String {
 }
 
 pub struct Env {
-    base: c::LPWCH,
+    base: *mut c::WCHAR,
     iter: EnvIterator,
 }
 
@@ -126,7 +127,7 @@ impl Iterator for Env {
 }
 
 #[derive(Clone)]
-struct EnvIterator(c::LPWCH);
+struct EnvIterator(*mut c::WCHAR);
 
 impl Iterator for EnvIterator {
     type Item = (OsString, OsString);
@@ -383,7 +384,7 @@ pub fn home_dir() -> Option<PathBuf> {
 }
 
 pub fn exit(code: i32) -> ! {
-    unsafe { c::ExitProcess(code as c::UINT) }
+    unsafe { c::ExitProcess(code as u32) }
 }
 
 pub fn getpid() -> u32 {
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 67ef3ca82da..d8b785f027c 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -1,3 +1,4 @@
+#![allow(unsafe_op_in_unsafe_fn)]
 use crate::os::windows::prelude::*;
 
 use crate::ffi::OsStr;
@@ -156,7 +157,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
         opts.share_mode(0);
         let size = mem::size_of::<c::SECURITY_ATTRIBUTES>();
         let mut sa = c::SECURITY_ATTRIBUTES {
-            nLength: size as c::DWORD,
+            nLength: size as u32,
             lpSecurityDescriptor: ptr::null_mut(),
             bInheritHandle: their_handle_inheritable as i32,
         };
@@ -225,9 +226,9 @@ fn random_number() -> usize {
 // Abstracts over `ReadFileEx` and `WriteFileEx`
 type AlertableIoFn = unsafe extern "system" fn(
     BorrowedHandle<'_>,
-    c::LPVOID,
-    c::DWORD,
-    c::LPOVERLAPPED,
+    *mut core::ffi::c_void,
+    u32,
+    *mut c::OVERLAPPED,
     c::LPOVERLAPPED_COMPLETION_ROUTINE,
 ) -> c::BOOL;
 
@@ -244,7 +245,7 @@ impl AnonPipe {
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let result = unsafe {
-            let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
+            let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32;
             self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len)
         };
 
@@ -260,7 +261,7 @@ impl AnonPipe {
 
     pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
         let result = unsafe {
-            let len = crate::cmp::min(buf.capacity(), c::DWORD::MAX as usize) as c::DWORD;
+            let len = crate::cmp::min(buf.capacity(), u32::MAX as usize) as u32;
             self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len)
         };
 
@@ -295,7 +296,7 @@ impl AnonPipe {
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         unsafe {
-            let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
+            let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32;
             self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len)
         }
     }
@@ -327,8 +328,8 @@ impl AnonPipe {
     unsafe fn alertable_io_internal(
         &self,
         io: AlertableIoFn,
-        buf: c::LPVOID,
-        len: c::DWORD,
+        buf: *mut core::ffi::c_void,
+        len: u32,
     ) -> io::Result<usize> {
         // Use "alertable I/O" to synchronize the pipe I/O.
         // This has four steps.
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index c62764696b8..76d2cb77d47 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -19,7 +19,7 @@ use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::sync::Mutex;
 use crate::sys::args::{self, Arg};
-use crate::sys::c::{self, NonZeroDWORD, EXIT_FAILURE, EXIT_SUCCESS};
+use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS};
 use crate::sys::cvt;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
@@ -174,7 +174,7 @@ pub struct Command {
 
 pub enum Stdio {
     Inherit,
-    InheritSpecific { from_stdio_id: c::DWORD },
+    InheritSpecific { from_stdio_id: u32 },
     Null,
     MakePipe,
     Pipe(AnonPipe),
@@ -364,7 +364,7 @@ impl Command {
             };
             si_ptr = core::ptr::addr_of_mut!(si_ex) as _;
         } else {
-            si.cb = mem::size_of::<c::STARTUPINFOW>() as c::DWORD;
+            si.cb = mem::size_of::<c::STARTUPINFOW>() as u32;
             si_ptr = core::ptr::addr_of_mut!(si) as _;
         }
 
@@ -566,7 +566,7 @@ fn program_exists(path: &Path) -> Option<Vec<u16>> {
 }
 
 impl Stdio {
-    fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
+    fn to_handle(&self, stdio_id: u32, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
         let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) {
             Ok(io) => unsafe {
                 let io = Handle::from_raw_handle(io);
@@ -601,7 +601,7 @@ impl Stdio {
             Stdio::Null => {
                 let size = mem::size_of::<c::SECURITY_ATTRIBUTES>();
                 let mut sa = c::SECURITY_ATTRIBUTES {
-                    nLength: size as c::DWORD,
+                    nLength: size as u32,
                     lpSecurityDescriptor: ptr::null_mut(),
                     bInheritHandle: 1,
                 };
@@ -713,11 +713,11 @@ impl Process {
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
-pub struct ExitStatus(c::DWORD);
+pub struct ExitStatus(u32);
 
 impl ExitStatus {
     pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        match NonZeroDWORD::try_from(self.0) {
+        match NonZero::<u32>::try_from(self.0) {
             /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
             /* was zero, couldn't convert */ Err(_) => Ok(()),
         }
@@ -727,9 +727,9 @@ impl ExitStatus {
     }
 }
 
-/// Converts a raw `c::DWORD` to a type-safe `ExitStatus` by wrapping it without copying.
-impl From<c::DWORD> for ExitStatus {
-    fn from(u: c::DWORD) -> ExitStatus {
+/// Converts a raw `u32` to a type-safe `ExitStatus` by wrapping it without copying.
+impl From<u32> for ExitStatus {
+    fn from(u: u32) -> ExitStatus {
         ExitStatus(u)
     }
 }
@@ -750,7 +750,7 @@ impl fmt::Display for ExitStatus {
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitStatusError(c::NonZeroDWORD);
+pub struct ExitStatusError(NonZero<u32>);
 
 impl Into<ExitStatus> for ExitStatusError {
     fn into(self) -> ExitStatus {
@@ -765,7 +765,7 @@ impl ExitStatusError {
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(c::DWORD);
+pub struct ExitCode(u32);
 
 impl ExitCode {
     pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
@@ -779,13 +779,13 @@ impl ExitCode {
 
 impl From<u8> for ExitCode {
     fn from(code: u8) -> Self {
-        ExitCode(c::DWORD::from(code))
+        ExitCode(u32::from(code))
     }
 }
 
 impl From<u32> for ExitCode {
     fn from(code: u32) -> Self {
-        ExitCode(c::DWORD::from(code))
+        ExitCode(u32::from(code))
     }
 }
 
diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs
index 09f527a09bf..e366bb99562 100644
--- a/library/std/src/sys/pal/windows/rand.rs
+++ b/library/std/src/sys/pal/windows/rand.rs
@@ -20,7 +20,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 
     let mut v = (0, 0);
     let ret = unsafe {
-        c::RtlGenRandom(ptr::addr_of_mut!(v).cast::<c_void>(), mem::size_of_val(&v) as c::ULONG)
+        c::RtlGenRandom(ptr::addr_of_mut!(v).cast::<c_void>(), mem::size_of_val(&v) as u32)
     };
 
     if ret != 0 { v } else { panic!("RNG broken: {}", io::Error::last_os_error()) }
diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs
index f93f31026f8..ea89429cb83 100644
--- a/library/std/src/sys/pal/windows/stack_overflow.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow.rs
@@ -1,4 +1,5 @@
 #![cfg_attr(test, allow(dead_code))]
+#![allow(unsafe_op_in_unsafe_fn)]
 
 use crate::sys::c;
 use crate::thread;
@@ -11,7 +12,7 @@ pub unsafe fn reserve_stack() {
     debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
 }
 
-unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG {
+unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 {
     unsafe {
         let rec = &(*(*ExceptionInfo).ExceptionRecord);
         let code = rec.ExceptionCode;
diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs
index 10aeeac07ea..c6a21665157 100644
--- a/library/std/src/sys/pal/windows/stdio.rs
+++ b/library/std/src/sys/pal/windows/stdio.rs
@@ -68,7 +68,7 @@ const MAX_BUFFER_SIZE: usize = 8192;
 // UTF-16 to UTF-8.
 pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3;
 
-pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> {
+pub fn get_handle(handle_id: u32) -> io::Result<c::HANDLE> {
     let handle = unsafe { c::GetStdHandle(handle_id) };
     if handle == c::INVALID_HANDLE_VALUE {
         Err(io::Error::last_os_error())
@@ -87,11 +87,7 @@ fn is_console(handle: c::HANDLE) -> bool {
     unsafe { c::GetConsoleMode(handle, &mut mode) != 0 }
 }
 
-fn write(
-    handle_id: c::DWORD,
-    data: &[u8],
-    incomplete_utf8: &mut IncompleteUtf8,
-) -> io::Result<usize> {
+fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> io::Result<usize> {
     if data.is_empty() {
         return Ok(0);
     }
@@ -182,12 +178,12 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
         // Note that this theoretically checks validity twice in the (most common) case
         // where the underlying byte sequence is valid utf-8 (given the check in `write()`).
         let result = c::MultiByteToWideChar(
-            c::CP_UTF8,                      // CodePage
-            c::MB_ERR_INVALID_CHARS,         // dwFlags
-            utf8.as_ptr(),                   // lpMultiByteStr
-            utf8.len() as c::c_int,          // cbMultiByte
-            utf16.as_mut_ptr() as c::LPWSTR, // lpWideCharStr
-            utf16.len() as c::c_int,         // cchWideChar
+            c::CP_UTF8,                          // CodePage
+            c::MB_ERR_INVALID_CHARS,             // dwFlags
+            utf8.as_ptr(),                       // lpMultiByteStr
+            utf8.len() as i32,                   // cbMultiByte
+            utf16.as_mut_ptr() as *mut c::WCHAR, // lpWideCharStr
+            utf16.len() as i32,                  // cchWideChar
         );
         assert!(result != 0, "Unexpected error in MultiByteToWideChar");
 
@@ -341,9 +337,9 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
     // traditional DOS method to indicate end of character stream / user input (SUB).
     // See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole.
     const CTRL_Z: u16 = 0x1A;
-    const CTRL_Z_MASK: c::ULONG = 1 << CTRL_Z;
+    const CTRL_Z_MASK: u32 = 1 << CTRL_Z;
     let input_control = c::CONSOLE_READCONSOLE_CONTROL {
-        nLength: crate::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
+        nLength: crate::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as u32,
         nInitialChars: 0,
         dwCtrlWakeupMask: CTRL_Z_MASK,
         dwControlKeyState: 0,
@@ -355,7 +351,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
             c::SetLastError(0);
             c::ReadConsoleW(
                 handle,
-                buf.as_mut_ptr() as c::LPVOID,
+                buf.as_mut_ptr() as *mut core::ffi::c_void,
                 buf.len() as u32,
                 &mut amount,
                 &input_control,
@@ -378,8 +374,8 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
 }
 
 fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
-    debug_assert!(utf16.len() <= c::c_int::MAX as usize);
-    debug_assert!(utf8.len() <= c::c_int::MAX as usize);
+    debug_assert!(utf16.len() <= i32::MAX as usize);
+    debug_assert!(utf8.len() <= i32::MAX as usize);
 
     if utf16.is_empty() {
         return Ok(0);
@@ -390,9 +386,9 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
             c::CP_UTF8,              // CodePage
             c::WC_ERR_INVALID_CHARS, // dwFlags
             utf16.as_ptr(),          // lpWideCharStr
-            utf16.len() as c::c_int, // cchWideChar
+            utf16.len() as i32,      // cchWideChar
             utf8.as_mut_ptr(),       // lpMultiByteStr
-            utf8.len() as c::c_int,  // cbMultiByte
+            utf8.len() as i32,       // cbMultiByte
             ptr::null(),             // lpDefaultChar
             ptr::null_mut(),         // lpUsedDefaultChar
         )
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 70099e0a3b5..3648272a343 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -1,3 +1,4 @@
+#![allow(unsafe_op_in_unsafe_fn)]
 use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
@@ -45,7 +46,7 @@ impl Thread {
             Err(io::Error::last_os_error())
         };
 
-        unsafe extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
+        unsafe extern "system" fn thread_start(main: *mut c_void) -> u32 {
             // Next, reserve some stack space for if we otherwise run out of stack.
             stack_overflow::reserve_stack();
             // Finally, let's run some code.
diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs
index 09e78a29304..b853daeffeb 100644
--- a/library/std/src/sys/pal/windows/time.rs
+++ b/library/std/src/sys/pal/windows/time.rs
@@ -76,8 +76,8 @@ impl SystemTime {
     fn from_intervals(intervals: i64) -> SystemTime {
         SystemTime {
             t: c::FILETIME {
-                dwLowDateTime: intervals as c::DWORD,
-                dwHighDateTime: (intervals >> 32) as c::DWORD,
+                dwLowDateTime: intervals as u32,
+                dwHighDateTime: (intervals >> 32) as u32,
             },
         }
     }
@@ -172,7 +172,7 @@ mod perf_counter {
     use crate::time::Duration;
 
     pub struct PerformanceCounterInstant {
-        ts: c::LARGE_INTEGER,
+        ts: i64,
     }
     impl PerformanceCounterInstant {
         pub fn now() -> Self {
@@ -196,7 +196,7 @@ mod perf_counter {
         }
     }
 
-    fn frequency() -> c::LARGE_INTEGER {
+    fn frequency() -> i64 {
         // Either the cached result of `QueryPerformanceFrequency` or `0` for
         // uninitialized. Storing this as a single `AtomicU64` allows us to use
         // `Relaxed` operations, as we are only interested in the effects on a
@@ -206,7 +206,7 @@ mod perf_counter {
         let cached = FREQUENCY.load(Ordering::Relaxed);
         // If a previous thread has filled in this global state, use that.
         if cached != 0 {
-            return cached as c::LARGE_INTEGER;
+            return cached as i64;
         }
         // ... otherwise learn for ourselves ...
         let mut frequency = 0;
@@ -218,8 +218,8 @@ mod perf_counter {
         frequency
     }
 
-    fn query() -> c::LARGE_INTEGER {
-        let mut qpc_value: c::LARGE_INTEGER = 0;
+    fn query() -> i64 {
+        let mut qpc_value: i64 = 0;
         cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap();
         qpc_value
     }
diff --git a/library/std/src/sys/sync/mutex/windows7.rs b/library/std/src/sys/sync/mutex/windows7.rs
index ef2f84082cd..689dba10f01 100644
--- a/library/std/src/sys/sync/mutex/windows7.rs
+++ b/library/std/src/sys/sync/mutex/windows7.rs
@@ -25,7 +25,7 @@ unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {}
 
 #[inline]
-pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
+pub unsafe fn raw(m: &Mutex) -> *mut c::SRWLOCK {
     m.srwlock.get()
 }
 
diff --git a/library/std/src/sys/sync/thread_parking/windows.rs b/library/std/src/sys/sync/thread_parking/windows.rs
index 4b8102d505a..3a8d40dc5cf 100644
--- a/library/std/src/sys/sync/thread_parking/windows.rs
+++ b/library/std/src/sys/sync/thread_parking/windows.rs
@@ -64,6 +64,7 @@ use crate::sync::atomic::{
 };
 use crate::sys::{c, dur2timeout};
 use crate::time::Duration;
+use core::ffi::c_void;
 
 pub struct Parker {
     state: AtomicI8,
@@ -117,7 +118,7 @@ impl Parker {
 
         loop {
             // Wait for something to happen, assuming it's still set to PARKED.
-            c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
+            c::WaitOnAddress(self.ptr(), &PARKED as *const _ as *const c_void, 1, c::INFINITE);
             // Change NOTIFIED=>EMPTY but leave PARKED alone.
             if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
                 // Actually woken up by unpark().
@@ -144,7 +145,7 @@ impl Parker {
         }
 
         // Wait for something to happen, assuming it's still set to PARKED.
-        c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
+        c::WaitOnAddress(self.ptr(), &PARKED as *const _ as *const c_void, 1, dur2timeout(timeout));
         // Set the state back to EMPTY (from either PARKED or NOTIFIED).
         // Note that we don't just write EMPTY, but use swap() to also
         // include an acquire-ordered read to synchronize with unpark()'s
@@ -177,8 +178,8 @@ impl Parker {
         }
     }
 
-    fn ptr(&self) -> c::LPVOID {
-        core::ptr::addr_of!(self.state) as c::LPVOID
+    fn ptr(&self) -> *const c_void {
+        core::ptr::addr_of!(self.state).cast::<c_void>()
     }
 }
 
diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs
index 81797f55170..f6cd457046f 100644
--- a/library/std/src/sys/thread_local/guard/windows.rs
+++ b/library/std/src/sys/thread_local/guard/windows.rs
@@ -65,6 +65,7 @@
 
 use crate::ptr;
 use crate::sys::c;
+use core::ffi::c_void;
 
 pub fn enable() {
     // When destructors are used, we don't want LLVM eliminating CALLBACK for any
@@ -74,9 +75,9 @@ pub fn enable() {
 
 #[link_section = ".CRT$XLB"]
 #[cfg_attr(miri, used)] // Miri only considers explicitly `#[used]` statics for `lookup_link_section`
-pub static CALLBACK: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) = tls_callback;
+pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) = tls_callback;
 
-unsafe extern "system" fn tls_callback(_h: c::LPVOID, dw_reason: c::DWORD, _pv: c::LPVOID) {
+unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) {
     // See comments above for what this is doing. Note that we don't need this
     // trickery on GNU windows, just on MSVC.
     #[cfg(all(target_env = "msvc", not(target_thread_local)))]
diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs
index baf23979c7c..8b43e558d5d 100644
--- a/library/std/src/sys/thread_local/key/windows.rs
+++ b/library/std/src/sys/thread_local/key/windows.rs
@@ -33,11 +33,11 @@ use crate::sync::atomic::{
 use crate::sys::c;
 use crate::sys::thread_local::guard;
 
-pub type Key = c::DWORD;
+pub type Key = u32;
 type Dtor = unsafe extern "C" fn(*mut u8);
 
 pub struct LazyKey {
-    /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == DWORD::MAX
+    /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == u32::MAX
     /// is not a valid key value, this allows us to use zero as sentinel value
     /// without risking overflow.
     key: AtomicU32,
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 117a3e23044..6aeeb625928 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -602,7 +602,8 @@ impl Wtf8 {
     /// marked unsafe.
     #[inline]
     pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 {
-        mem::transmute(value)
+        // SAFETY: start with &[u8], end with fancy &[u8]
+        unsafe { &*(value as *const [u8] as *const Wtf8) }
     }
 
     /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice.
@@ -611,7 +612,8 @@ impl Wtf8 {
     /// marked unsafe.
     #[inline]
     unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 {
-        mem::transmute(value)
+        // SAFETY: start with &mut [u8], end with fancy &mut [u8]
+        unsafe { &mut *(value as *mut [u8] as *mut Wtf8) }
     }
 
     /// Returns the length, in WTF-8 bytes.
@@ -942,8 +944,12 @@ pub fn check_utf8_boundary(slice: &Wtf8, index: usize) {
 /// Copied from core::str::raw::slice_unchecked
 #[inline]
 pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {
-    // memory layout of a &[u8] and &Wtf8 are the same
-    Wtf8::from_bytes_unchecked(slice::from_raw_parts(s.bytes.as_ptr().add(begin), end - begin))
+    // SAFETY: memory layout of a &[u8] and &Wtf8 are the same
+    unsafe {
+        let len = end - begin;
+        let start = s.as_bytes().as_ptr().add(begin);
+        Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len))
+    }
 }
 
 /// Copied from core::str::raw::slice_error_fail
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index 1ddacd92e6b..169eeeca8c2 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -27,3 +27,4 @@ profiler = ["std/profiler"]
 std_detect_file_io = ["std/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]
 std_detect_env_override = ["std/std_detect_env_override"]
+windows_raw_dylib = ["std/windows_raw_dylib"]
diff --git a/rustfmt.toml b/rustfmt.toml
index b15ffdca38a..e060fd8fe8b 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -22,6 +22,8 @@ ignore = [
     "/tests/rustdoc-ui/",             # Some have syntax errors, some are whitespace-sensitive.
     "/tests/ui/",                     # Some have syntax errors, some are whitespace-sensitive.
     "/tests/ui-fulldeps/",            # Some are whitespace-sensitive (e.g. `// ~ERROR` comments).
+    # #[cfg(bootstrap)] so that t-release sees this when they search for it
+    "/tests/rustdoc-json/impl-trait-precise-capturing.rs",
 
     # Do not format submodules.
     # FIXME: sync submodule list with tidy/bootstrap/etc
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index c095127da14..de0924c0f42 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -48,7 +48,6 @@ dependencies = [
  "clap_complete",
  "cmake",
  "fd-lock",
- "filetime",
  "home",
  "ignore",
  "junction",
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index df7b5b88193..f723407c3ce 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -44,7 +44,6 @@ build_helper = { path = "../tools/build_helper" }
 clap = { version = "4.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
 clap_complete = "4.4"
 fd-lock = "4.0"
-filetime = "0.2"
 home = "0.5"
 ignore = "0.4"
 libc = "0.2"
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index fb3c8627043..0ac58645d2d 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -1,7 +1,7 @@
-# rustbuild - Bootstrapping Rust
+# Bootstrapping Rust
 
 This README is aimed at helping to explain how Rust is bootstrapped,
-and some of the technical details of the build system.
+and some of the technical details of the bootstrap build system.
 
 Note that this README only covers internal information, not how to use the tool.
 Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information.
@@ -12,17 +12,17 @@ Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further info
 
 The build system defers most of the complicated logic of managing invocations
 of rustc and rustdoc to Cargo itself. However, moving through various stages
-and copying artifacts is still necessary for it to do. Each time rustbuild
+and copying artifacts is still necessary for it to do. Each time bootstrap
 is invoked, it will iterate through the list of predefined steps and execute
 each serially in turn if it matches the paths passed or is a default rule.
-For each step, rustbuild relies on the step internally being incremental and
-parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded
+For each step, bootstrap relies on the step internally being incremental and
+parallel. Note, though, that the `-j` parameter to bootstrap gets forwarded
 to appropriate test harnesses and such.
 
 ## Build phases
 
-The rustbuild build system goes through a few phases to actually build the
-compiler. What actually happens when you invoke rustbuild is:
+Bootstrap build system goes through a few phases to actually build the
+compiler. What actually happens when you invoke bootstrap is:
 
 1. The entry point script (`x` for unix like systems, `x.ps1` for windows systems,
    `x.py` cross-platform) is run. This script is responsible for downloading the stage0
@@ -151,9 +151,9 @@ build/
     stage3/
 ```
 
-## Extending rustbuild
+## Extending bootstrap
 
-When you use the bootstrap system, you'll call it through the entry point script
+When you use bootstrap, you'll call it through the entry point script
 (`x`, `x.ps1`, or `x.py`). However, most of the code lives in `src/bootstrap`.
 `bootstrap` has a difficult problem: it is written in Rust, but yet it is run
 before the Rust compiler is built! To work around this, there are two components
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 7e47b373ff9..4e8e0fd2532 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1038,7 +1038,7 @@ class RustBuild(object):
 
     def check_vendored_status(self):
         """Check that vendoring is configured properly"""
-        # keep this consistent with the equivalent check in rustbuild:
+        # keep this consistent with the equivalent check in bootstrap:
         # https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/lib.rs#L399-L405
         if 'SUDO_USER' in os.environ and not self.use_vendored_sources:
             if os.getuid() == 0:
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index cab37e0da47..7e38a0996e5 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -20,7 +20,7 @@ all:
 	$(Q)$(BOOTSTRAP) doc --stage 2 $(BOOTSTRAP_ARGS)
 
 help:
-	$(Q)echo 'Welcome to the rustbuild build system!'
+	$(Q)echo 'Welcome to bootstrap, the Rust build system!'
 	$(Q)echo
 	$(Q)echo This makefile is a thin veneer over the ./x.py script located
 	$(Q)echo in this directory. To get the full power of the build system
@@ -58,9 +58,8 @@ check-aux:
 		library/core \
 		library/alloc \
 		--no-doc
-	# Some doctests have intentional memory leaks.
-	# Some use file system operations to demonstrate dealing with `Result`.
-	$(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \
+	# Some doctests use file system operations to demonstrate dealing with `Result`.
+	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
 		$(BOOTSTRAP) miri --stage 2 \
 		library/core \
 		library/alloc \
@@ -70,7 +69,7 @@ check-aux:
 		$(BOOTSTRAP) miri --stage 2 library/std \
 		--no-doc -- \
 		--skip fs:: --skip net:: --skip process:: --skip sys::pal::
-	$(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \
+	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
 		$(BOOTSTRAP) miri --stage 2 library/std \
 		--doc -- \
 		--skip fs:: --skip net:: --skip process:: --skip sys::pal::
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index 44fb1911fc6..a7d21ba6ae1 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -1,4 +1,4 @@
-//! rustbuild, the Rust build system
+//! bootstrap, the Rust build system
 //!
 //! This is the entry point for the build system used to compile the `rustc`
 //! compiler. Lots of documentation can be found in the `README.md` file in the
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 11a7a404535..ba2ad53a94e 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1,7 +1,7 @@
 //! Implementation of compiling various phases of the compiler and standard
 //! library.
 //!
-//! This module contains some of the real meat in the rustbuild build system
+//! This module contains some of the real meat in the bootstrap build system
 //! which is where Cargo is used to compile the standard library, libtest, and
 //! the compiler. This module is also responsible for assembling the sysroot as it
 //! goes along from the output of the previous stage.
@@ -14,7 +14,7 @@ use std::fs;
 use std::io::prelude::*;
 use std::io::BufReader;
 use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
+use std::process::Stdio;
 use std::str;
 
 use serde_derive::Deserialize;
@@ -33,7 +33,6 @@ use crate::utils::helpers::{
 };
 use crate::LLVM_TOOLS;
 use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
-use filetime::FileTime;
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Std {
@@ -696,10 +695,10 @@ fn copy_sanitizers(
             || target == "x86_64-apple-ios"
         {
             // Update the library’s install name to reflect that it has been renamed.
-            apple_darwin_update_library_name(&dst, &format!("@rpath/{}", &runtime.name));
+            apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", &runtime.name));
             // Upon renaming the install name, the code signature of the file will invalidate,
             // so we will sign it again.
-            apple_darwin_sign_file(&dst);
+            apple_darwin_sign_file(builder, &dst);
         }
 
         target_deps.push(dst);
@@ -708,25 +707,17 @@ fn copy_sanitizers(
     target_deps
 }
 
-fn apple_darwin_update_library_name(library_path: &Path, new_name: &str) {
-    let status = Command::new("install_name_tool")
-        .arg("-id")
-        .arg(new_name)
-        .arg(library_path)
-        .status()
-        .expect("failed to execute `install_name_tool`");
-    assert!(status.success());
+fn apple_darwin_update_library_name(builder: &Builder<'_>, library_path: &Path, new_name: &str) {
+    command("install_name_tool").arg("-id").arg(new_name).arg(library_path).run(builder);
 }
 
-fn apple_darwin_sign_file(file_path: &Path) {
-    let status = Command::new("codesign")
+fn apple_darwin_sign_file(builder: &Builder<'_>, file_path: &Path) {
+    command("codesign")
         .arg("-f") // Force to rewrite the existing signature
         .arg("-s")
         .arg("-")
         .arg(file_path)
-        .status()
-        .expect("failed to execute `codesign`");
-    assert!(status.success());
+        .run(builder);
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -818,8 +809,8 @@ pub struct Rustc {
     pub compiler: Compiler,
     /// Whether to build a subset of crates, rather than the whole compiler.
     ///
-    /// This should only be requested by the user, not used within rustbuild itself.
-    /// Using it within rustbuild can lead to confusing situation where lints are replayed
+    /// This should only be requested by the user, not used within bootstrap itself.
+    /// Using it within bootstrap can lead to confusing situation where lints are replayed
     /// in two different steps.
     crates: Vec<String>,
 }
@@ -1172,7 +1163,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
     if builder.config.llvm_profile_generate && target.is_msvc() {
         if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl {
             // Add clang's runtime library directory to the search path
-            let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
+            let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
             llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
         }
     }
@@ -1213,8 +1204,8 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
     if builder.config.llvm_use_libcxx {
         cargo.env("LLVM_USE_LIBCXX", "1");
     }
-    if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
-        cargo.env("LLVM_NDEBUG", "1");
+    if builder.config.llvm_assertions {
+        cargo.env("LLVM_ASSERTIONS", "1");
     }
 }
 
@@ -2080,7 +2071,8 @@ pub fn stream_cargo(
     tail_args: Vec<String>,
     cb: &mut dyn FnMut(CargoMessage<'_>),
 ) -> bool {
-    let mut cargo = cargo.into_cmd().command;
+    let mut cmd = cargo.into_cmd();
+    let cargo = cmd.as_command_mut();
     // Instruct Cargo to give us json messages on stdout, critically leaving
     // stderr as piped so we can get those pretty colors.
     let mut message_format = if builder.config.json_output {
@@ -2160,9 +2152,11 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path)
         return;
     }
 
-    let previous_mtime = FileTime::from_last_modification_time(&path.metadata().unwrap());
+    let previous_mtime = t!(t!(path.metadata()).modified());
     command("strip").capture().arg("--strip-debug").arg(path).run(builder);
 
+    let file = t!(fs::File::open(path));
+
     // After running `strip`, we have to set the file modification time to what it was before,
     // otherwise we risk Cargo invalidating its fingerprint and rebuilding the world next time
     // bootstrap is invoked.
@@ -2175,5 +2169,5 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path)
     // In the second invocation of bootstrap, Cargo will see that the mtime of librustc_driver.so
     // is greater than the mtime of rustc-main, and will rebuild rustc-main. That will then cause
     // everything else (standard library, future stages...) to be rebuilt.
-    t!(filetime::set_file_mtime(path, previous_mtime));
+    t!(file.set_modified(previous_mtime));
 }
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 7bc5405e92f..1e9d2025bc7 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1060,11 +1060,7 @@ impl Step for PlainSourceTarball {
                 cmd.arg("--sync").arg(manifest_path);
             }
 
-            let config = if !builder.config.dry_run() {
-                cmd.capture().run(builder).stdout()
-            } else {
-                String::new()
-            };
+            let config = cmd.capture().run(builder).stdout();
 
             let cargo_config_dir = plain_dst_src.join(".cargo");
             builder.create_dir(&cargo_config_dir);
@@ -2072,11 +2068,7 @@ fn maybe_install_llvm(
         let mut cmd = command(llvm_config);
         cmd.arg("--libfiles");
         builder.verbose(|| println!("running {cmd:?}"));
-        let files = if builder.config.dry_run() {
-            "".into()
-        } else {
-            cmd.capture_stdout().run(builder).stdout()
-        };
+        let files = cmd.capture_stdout().run(builder).stdout();
         let build_llvm_out = &builder.llvm_out(builder.config.build);
         let target_llvm_out = &builder.llvm_out(target);
         for file in files.trim_end().split(' ') {
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 4b35d6c5d4c..633e66afe59 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -1,4 +1,4 @@
-//! Documentation generation for rustbuilder.
+//! Documentation generation for bootstrap.
 //!
 //! This module implements generation for all bits and pieces of documentation
 //! for the Rust project. This notably includes suites like the rust book, the
@@ -146,7 +146,6 @@ impl<P: Step> Step for RustbookSrc<P> {
         let out = out.join(&name);
         let index = out.join("index.html");
         let rustbook = builder.tool_exe(Tool::Rustbook);
-        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
 
         if !builder.config.dry_run()
             && (!up_to_date(&src, &index) || !up_to_date(&rustbook, &index))
@@ -154,7 +153,13 @@ impl<P: Step> Step for RustbookSrc<P> {
             builder.info(&format!("Rustbook ({target}) - {name}"));
             let _ = fs::remove_dir_all(&out);
 
-            rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder);
+            builder
+                .tool_cmd(Tool::Rustbook)
+                .arg("build")
+                .arg(&src)
+                .arg("-d")
+                .arg(&out)
+                .run(builder);
 
             for lang in &self.languages {
                 let out = out.join(lang);
@@ -253,10 +258,6 @@ impl Step for TheBook {
         // build the version info page and CSS
         let shared_assets = builder.ensure(SharedAssets { target });
 
-        // build the command first so we don't nest GHA groups
-        // FIXME: this doesn't do anything!
-        builder.rustdoc_cmd(compiler);
-
         // build the redirect pages
         let _guard = builder.msg_doc(compiler, "book redirect pages", target);
         for file in t!(fs::read_dir(redirect_path)) {
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 872823506f8..888290a0479 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -125,6 +125,7 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
     static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
     let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
         generate_smart_stamp_hash(
+            builder,
             &builder.config.src.join("src/llvm-project"),
             builder.in_tree_llvm_info.sha().unwrap_or_default(),
         )
@@ -172,7 +173,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
             // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
             config.src.join("src/version"),
         ]);
-        output(&mut rev_list.command).trim().to_owned()
+        output(rev_list.as_command_mut()).trim().to_owned()
     } else if let Some(info) = channel::read_commit_info_file(&config.src) {
         info.sha.trim().to_owned()
     } else {
@@ -254,7 +255,7 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool {
         // `true` here.
         let llvm_sha = detect_llvm_sha(config, true);
         let head_sha =
-            output(&mut helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").command);
+            output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").as_command_mut());
         let head_sha = head_sha.trim();
         llvm_sha == head_sha
     }
@@ -912,7 +913,7 @@ impl Step for Lld {
             if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() {
                 // Find clang's runtime library directory and push that as a search path to the
                 // cmake linker flags.
-                let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
+                let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
                 ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
             }
         }
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index e6a09e8cb8e..226b3729c10 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -8,6 +8,7 @@
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::t;
 use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY;
+use crate::utils::exec::command;
 use crate::utils::helpers::{self, hex_encode};
 use crate::Config;
 use sha2::Digest;
@@ -16,7 +17,6 @@ use std::fmt::Write as _;
 use std::fs::File;
 use std::io::Write;
 use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR};
-use std::process::Command;
 use std::str::FromStr;
 use std::{fmt, fs, io};
 
@@ -266,20 +266,16 @@ impl Step for Link {
         }
         let stage_path =
             ["build", config.build.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR);
-        if !rustup_installed() {
+        if !rustup_installed(builder) {
             eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
         } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
-            attempt_toolchain_link(&stage_path[..]);
+            attempt_toolchain_link(builder, &stage_path[..]);
         }
     }
 }
 
-fn rustup_installed() -> bool {
-    Command::new("rustup")
-        .arg("--version")
-        .stdout(std::process::Stdio::null())
-        .output()
-        .map_or(false, |output| output.status.success())
+fn rustup_installed(builder: &Builder<'_>) -> bool {
+    command("rustup").capture_stdout().arg("--version").run(builder).is_success()
 }
 
 fn stage_dir_exists(stage_path: &str) -> bool {
@@ -289,8 +285,8 @@ fn stage_dir_exists(stage_path: &str) -> bool {
     }
 }
 
-fn attempt_toolchain_link(stage_path: &str) {
-    if toolchain_is_linked() {
+fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) {
+    if toolchain_is_linked(builder) {
         return;
     }
 
@@ -301,7 +297,7 @@ fn attempt_toolchain_link(stage_path: &str) {
         return;
     }
 
-    if try_link_toolchain(stage_path) {
+    if try_link_toolchain(builder, stage_path) {
         println!(
             "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
         );
@@ -315,14 +311,16 @@ fn attempt_toolchain_link(stage_path: &str) {
     }
 }
 
-fn toolchain_is_linked() -> bool {
-    match Command::new("rustup")
+fn toolchain_is_linked(builder: &Builder<'_>) -> bool {
+    match command("rustup")
+        .capture_stdout()
+        .allow_failure()
         .args(["toolchain", "list"])
-        .stdout(std::process::Stdio::piped())
-        .output()
+        .run(builder)
+        .stdout_if_ok()
     {
-        Ok(toolchain_list) => {
-            if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") {
+        Some(toolchain_list) => {
+            if !toolchain_list.contains("stage1") {
                 return false;
             }
             // The toolchain has already been linked.
@@ -330,7 +328,7 @@ fn toolchain_is_linked() -> bool {
                 "`stage1` toolchain already linked; not attempting to link `stage1` toolchain"
             );
         }
-        Err(_) => {
+        None => {
             // In this case, we don't know if the `stage1` toolchain has been linked;
             // but `rustup` failed, so let's not go any further.
             println!(
@@ -341,12 +339,12 @@ fn toolchain_is_linked() -> bool {
     true
 }
 
-fn try_link_toolchain(stage_path: &str) -> bool {
-    Command::new("rustup")
-        .stdout(std::process::Stdio::null())
+fn try_link_toolchain(builder: &Builder<'_>, stage_path: &str) -> bool {
+    command("rustup")
+        .capture_stdout()
         .args(["toolchain", "link", "stage1", stage_path])
-        .output()
-        .map_or(false, |output| output.status.success())
+        .run(builder)
+        .is_success()
 }
 
 fn ensure_stage1_toolchain_placeholder_exists(stage_path: &str) -> bool {
@@ -476,20 +474,18 @@ impl Step for Hook {
         if config.dry_run() {
             return;
         }
-        t!(install_git_hook_maybe(config));
+        t!(install_git_hook_maybe(builder, config));
     }
 }
 
 // install a git hook to automatically run tidy, if they want
-fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
+fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<()> {
     let git = helpers::git(Some(&config.src))
+        .capture()
         .args(["rev-parse", "--git-common-dir"])
-        .command
-        .output()
-        .map(|output| {
-            assert!(output.status.success(), "failed to run `git`");
-            PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
-        })?;
+        .run(builder)
+        .stdout();
+    let git = PathBuf::from(git.trim());
     let hooks_dir = git.join("hooks");
     let dst = hooks_dir.join("pre-push");
     if dst.exists() {
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 0b60587bb79..3f0cbde64e3 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -9,7 +9,6 @@ use std::ffi::OsString;
 use std::fs;
 use std::iter;
 use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
 
 use clap_complete::shells;
 
@@ -169,12 +168,8 @@ You can skip linkcheck with --skip src/tools/linkchecker"
     }
 }
 
-fn check_if_tidy_is_installed() -> bool {
-    Command::new("tidy")
-        .arg("--version")
-        .stdout(Stdio::null())
-        .status()
-        .map_or(false, |status| status.success())
+fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool {
+    command("tidy").capture_stdout().allow_failure().arg("--version").run(builder).is_success()
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -188,8 +183,9 @@ impl Step for HtmlCheck {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        let builder = run.builder;
         let run = run.path("src/tools/html-checker");
-        run.lazy_default_condition(Box::new(check_if_tidy_is_installed))
+        run.lazy_default_condition(Box::new(|| check_if_tidy_is_installed(builder)))
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -197,7 +193,7 @@ impl Step for HtmlCheck {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        if !check_if_tidy_is_installed() {
+        if !check_if_tidy_is_installed(builder) {
             eprintln!("not running HTML-check tool because `tidy` is missing");
             eprintln!(
                 "You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager."
@@ -471,16 +467,12 @@ impl Miri {
         // We re-use the `cargo` from above.
         cargo.arg("--print-sysroot");
 
-        if builder.config.dry_run() {
-            String::new()
-        } else {
-            builder.verbose(|| println!("running: {cargo:?}"));
-            let stdout = cargo.capture_stdout().run(builder).stdout();
-            // Output is "<sysroot>\n".
-            let sysroot = stdout.trim_end();
-            builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
-            sysroot.to_owned()
-        }
+        builder.verbose(|| println!("running: {cargo:?}"));
+        let stdout = cargo.capture_stdout().run(builder).stdout();
+        // Output is "<sysroot>\n".
+        let sysroot = stdout.trim_end();
+        builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
+        sysroot.to_owned()
     }
 }
 
@@ -686,6 +678,8 @@ impl Step for CompiletestTest {
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
+            // compiletest uses libtest internals; make it use the in-tree std to make sure it never breaks
+            // when std sources change.
             Mode::ToolStd,
             host,
             "test",
@@ -1325,13 +1319,12 @@ impl Step for CrateRunMakeSupport {
     /// Runs `cargo test` for run-make-support.
     fn run(self, builder: &Builder<'_>) {
         let host = self.host;
-        let compiler = builder.compiler(builder.top_stage, host);
+        let compiler = builder.compiler(0, host);
 
-        builder.ensure(compile::Std::new(compiler, host));
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
-            Mode::ToolStd,
+            Mode::ToolBootstrap,
             host,
             "test",
             "src/tools/run-make-support",
@@ -1352,6 +1345,52 @@ impl Step for CrateRunMakeSupport {
     }
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct CrateBuildHelper {
+    host: TargetSelection,
+}
+
+impl Step for CrateBuildHelper {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/build_helper")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(CrateBuildHelper { host: run.target });
+    }
+
+    /// Runs `cargo test` for build_helper.
+    fn run(self, builder: &Builder<'_>) {
+        let host = self.host;
+        let compiler = builder.compiler(0, host);
+
+        let mut cargo = tool::prepare_tool_cargo(
+            builder,
+            compiler,
+            Mode::ToolBootstrap,
+            host,
+            "test",
+            "src/tools/build_helper",
+            SourceType::InTree,
+            &[],
+        );
+        cargo.allow_features("test");
+        run_cargo_test(
+            cargo,
+            &[],
+            &[],
+            "build_helper",
+            "build_helper self test",
+            compiler,
+            host,
+            builder,
+        );
+    }
+}
+
 default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" });
 
 default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" });
@@ -2056,9 +2095,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         let git_config = builder.config.git_config();
         cmd.arg("--git-repository").arg(git_config.git_repository);
         cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
-
-        // FIXME: Move CiEnv back to bootstrap, it is only used here anyway
-        builder.ci_env.force_coloring_in_ci(&mut cmd.command);
+        cmd.force_coloring_in_ci(builder.ci_env);
 
         #[cfg(feature = "build-metrics")]
         builder.metrics.begin_test_suite(
@@ -3001,7 +3038,7 @@ impl Step for Bootstrap {
             // https://github.com/rust-lang/rust/issues/49215
             cmd.env("RUSTFLAGS", flags);
         }
-        // rustbuild tests are racy on directory creation so just run them one at a time.
+        // bootstrap tests are racy on directory creation so just run them one at a time.
         // Since there's not many this shouldn't be a problem.
         run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder);
     }
diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs
index e3e7931a5a2..2ab0ce7454b 100644
--- a/src/bootstrap/src/core/build_steps/toolstate.rs
+++ b/src/bootstrap/src/core/build_steps/toolstate.rs
@@ -99,24 +99,16 @@ fn print_error(tool: &str, submodule: &str) {
     crate::exit!(3);
 }
 
-fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
+fn check_changed_files(builder: &Builder<'_>, toolstates: &HashMap<Box<str>, ToolState>) {
     // Changed files
     let output = helpers::git(None)
+        .capture()
         .arg("diff")
         .arg("--name-status")
         .arg("HEAD")
         .arg("HEAD^")
-        .command
-        .output();
-    let output = match output {
-        Ok(o) => o,
-        Err(e) => {
-            eprintln!("Failed to get changed files: {e:?}");
-            crate::exit!(1);
-        }
-    };
-
-    let output = t!(String::from_utf8(output.stdout));
+        .run(builder)
+        .stdout();
 
     for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) {
         let changed = output.lines().any(|l| l.starts_with('M') && l.ends_with(submodule));
@@ -186,8 +178,8 @@ impl Step for ToolStateCheck {
             crate::exit!(1);
         }
 
-        check_changed_files(&toolstates);
-        checkout_toolstate_repo();
+        check_changed_files(builder, &toolstates);
+        checkout_toolstate_repo(builder);
         let old_toolstate = read_old_toolstate();
 
         for (tool, _) in STABLE_TOOLS.iter() {
@@ -231,7 +223,7 @@ impl Step for ToolStateCheck {
         }
 
         if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() {
-            commit_toolstate_change(&toolstates);
+            commit_toolstate_change(builder, &toolstates);
         }
     }
 
@@ -315,50 +307,34 @@ fn toolstate_repo() -> String {
 const TOOLSTATE_DIR: &str = "rust-toolstate";
 
 /// Checks out the toolstate repo into `TOOLSTATE_DIR`.
-fn checkout_toolstate_repo() {
+fn checkout_toolstate_repo(builder: &Builder<'_>) {
     if let Ok(token) = env::var("TOOLSTATE_REPO_ACCESS_TOKEN") {
-        prepare_toolstate_config(&token);
+        prepare_toolstate_config(builder, &token);
     }
     if Path::new(TOOLSTATE_DIR).exists() {
         eprintln!("Cleaning old toolstate directory...");
         t!(fs::remove_dir_all(TOOLSTATE_DIR));
     }
 
-    let status = helpers::git(None)
+    helpers::git(None)
         .arg("clone")
         .arg("--depth=1")
         .arg(toolstate_repo())
         .arg(TOOLSTATE_DIR)
-        .command
-        .status();
-    let success = match status {
-        Ok(s) => s.success(),
-        Err(_) => false,
-    };
-    if !success {
-        panic!("git clone unsuccessful (status: {status:?})");
-    }
+        .run(builder);
 }
 
 /// Sets up config and authentication for modifying the toolstate repo.
-fn prepare_toolstate_config(token: &str) {
-    fn git_config(key: &str, value: &str) {
-        let status =
-            helpers::git(None).arg("config").arg("--global").arg(key).arg(value).command.status();
-        let success = match status {
-            Ok(s) => s.success(),
-            Err(_) => false,
-        };
-        if !success {
-            panic!("git config key={key} value={value} failed (status: {status:?})");
-        }
+fn prepare_toolstate_config(builder: &Builder<'_>, token: &str) {
+    fn git_config(builder: &Builder<'_>, key: &str, value: &str) {
+        helpers::git(None).arg("config").arg("--global").arg(key).arg(value).run(builder);
     }
 
     // If changing anything here, then please check that `src/ci/publish_toolstate.sh` is up to date
     // as well.
-    git_config("user.email", "7378925+rust-toolstate-update@users.noreply.github.com");
-    git_config("user.name", "Rust Toolstate Update");
-    git_config("credential.helper", "store");
+    git_config(builder, "user.email", "7378925+rust-toolstate-update@users.noreply.github.com");
+    git_config(builder, "user.name", "Rust Toolstate Update");
+    git_config(builder, "credential.helper", "store");
 
     let credential = format!("https://{token}:x-oauth-basic@github.com\n",);
     let git_credential_path = PathBuf::from(t!(env::var("HOME"))).join(".git-credentials");
@@ -398,55 +374,51 @@ fn read_old_toolstate() -> Vec<RepoState> {
 ///
 ///       * See <https://help.github.com/articles/about-commit-email-addresses/>
 ///           if a private email by GitHub is wanted.
-fn commit_toolstate_change(current_toolstate: &ToolstateData) {
+fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateData) {
     let message = format!("({} CI update)", OS.expect("linux/windows only"));
     let mut success = false;
     for _ in 1..=5 {
         // Upload the test results (the new commit-to-toolstate mapping) to the toolstate repo.
         // This does *not* change the "current toolstate"; that only happens post-landing
         // via `src/ci/docker/publish_toolstate.sh`.
-        publish_test_results(current_toolstate);
+        publish_test_results(builder, current_toolstate);
 
         // `git commit` failing means nothing to commit.
-        let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
+        let status = helpers::git(Some(Path::new(TOOLSTATE_DIR)))
+            .allow_failure()
             .arg("commit")
             .arg("-a")
             .arg("-m")
             .arg(&message)
-            .command
-            .status());
-        if !status.success() {
+            .run(builder);
+        if !status.is_success() {
             success = true;
             break;
         }
 
-        let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
+        let status = helpers::git(Some(Path::new(TOOLSTATE_DIR)))
+            .allow_failure()
             .arg("push")
             .arg("origin")
             .arg("master")
-            .command
-            .status());
+            .run(builder);
         // If we successfully push, exit.
-        if status.success() {
+        if status.is_success() {
             success = true;
             break;
         }
         eprintln!("Sleeping for 3 seconds before retrying push");
         std::thread::sleep(std::time::Duration::from_secs(3));
-        let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
+        helpers::git(Some(Path::new(TOOLSTATE_DIR)))
             .arg("fetch")
             .arg("origin")
             .arg("master")
-            .command
-            .status());
-        assert!(status.success());
-        let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
+            .run(builder);
+        helpers::git(Some(Path::new(TOOLSTATE_DIR)))
             .arg("reset")
             .arg("--hard")
             .arg("origin/master")
-            .command
-            .status());
-        assert!(status.success());
+            .run(builder);
     }
 
     if !success {
@@ -459,9 +431,8 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
 /// These results will later be promoted to `latest.json` by the
 /// `publish_toolstate.py` script if the PR passes all tests and is merged to
 /// master.
-fn publish_test_results(current_toolstate: &ToolstateData) {
-    let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").command.output());
-    let commit = t!(String::from_utf8(commit.stdout));
+fn publish_test_results(builder: &Builder<'_>, current_toolstate: &ToolstateData) {
+    let commit = helpers::git(None).capture().arg("rev-parse").arg("HEAD").run(builder).stdout();
 
     let toolstate_serialized = t!(serde_json::to_string(&current_toolstate));
 
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 65cc1fa7478..ebd62bb032f 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -860,6 +860,7 @@ impl<'a> Builder<'a> {
                 test::Clippy,
                 test::CompiletestTest,
                 test::CrateRunMakeSupport,
+                test::CrateBuildHelper,
                 test::RustdocJSStd,
                 test::RustdocJSNotStd,
                 test::RustdocGUI,
@@ -1626,11 +1627,11 @@ impl<'a> Builder<'a> {
         }
 
         // This tells Cargo (and in turn, rustc) to output more complete
-        // dependency information.  Most importantly for rustbuild, this
+        // dependency information.  Most importantly for bootstrap, this
         // includes sysroot artifacts, like libstd, which means that we don't
-        // need to track those in rustbuild (an error prone process!). This
+        // need to track those in bootstrap (an error prone process!). This
         // feature is currently unstable as there may be some bugs and such, but
-        // it represents a big improvement in rustbuild's reliability on
+        // it represents a big improvement in bootstrap's reliability on
         // rebuilds, so we're using it here.
         //
         // For some additional context, see #63470 (the PR originally adding
@@ -1642,7 +1643,7 @@ impl<'a> Builder<'a> {
                 // Restrict the allowed features so we don't depend on nightly
                 // accidentally.
                 //
-                // binary-dep-depinfo is used by rustbuild itself for all
+                // binary-dep-depinfo is used by bootstrap itself for all
                 // compilations.
                 //
                 // Lots of tools depend on proc_macro2 and proc-macro-error.
@@ -1997,6 +1998,9 @@ impl<'a> Builder<'a> {
         if mode == Mode::Rustc {
             rustflags.arg("-Zunstable-options");
             rustflags.arg("-Wrustc::internal");
+            // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all
+            // of the individual lints are satisfied.
+            rustflags.arg("-Wkeyword_idents_2024");
         }
 
         if self.config.rust_frame_pointers {
@@ -2104,7 +2108,7 @@ impl<'a> Builder<'a> {
         // Try to use a sysroot-relative bindir, in case it was configured absolutely.
         cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative());
 
-        self.ci_env.force_coloring_in_ci(&mut cargo.command);
+        cargo.force_coloring_in_ci(self.ci_env);
 
         // When we build Rust dylibs they're all intended for intermediate
         // usage, so make sure we pass the -Cprefer-dynamic flag instead of
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index aa119b8c699..97c9ece0036 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -266,7 +266,7 @@ mod defaults {
         // rustdoc/rustcc/std here (the user only requested a host=B build, so
         // there's not really a need for us to build for target A in this case
         // (since we're producing stage 1 libraries/binaries).  But currently
-        // rustbuild is just a bit buggy here; this should be fixed though.
+        // bootstrap is just a bit buggy here; this should be fixed though.
         assert_eq!(
             first(cache.all::<compile::Std>()),
             &[
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 2d54a84331f..f96633b059a 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -33,7 +33,7 @@ macro_rules! check_ci_llvm {
         assert!(
             $name.is_none(),
             "setting {} is incompatible with download-ci-llvm.",
-            stringify!($name)
+            stringify!($name).replace("_", "-")
         );
     };
 }
@@ -658,8 +658,7 @@ impl Merge for TomlConfig {
     }
 }
 
-// We are using a decl macro instead of a derive proc macro here to reduce the compile time of
-// rustbuild.
+// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap.
 macro_rules! define_config {
     ($(#[$attr:meta])* struct $name:ident {
         $($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
@@ -704,7 +703,7 @@ macro_rules! define_config {
 
         // The following is a trimmed version of what serde_derive generates. All parts not relevant
         // for toml deserialization have been removed. This reduces the binary size and improves
-        // compile time of rustbuild.
+        // compile time of bootstrap.
         impl<'de> Deserialize<'de> for $name {
             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
             where
@@ -1259,7 +1258,7 @@ impl Config {
         cmd.arg("rev-parse").arg("--show-cdup");
         // Discard stderr because we expect this to fail when building from a tarball.
         let output = cmd
-            .command
+            .as_command_mut()
             .stderr(std::process::Stdio::null())
             .output()
             .ok()
@@ -1569,7 +1568,15 @@ impl Config {
         let mut lld_enabled = None;
 
         let mut is_user_configured_rust_channel = false;
+
         if let Some(rust) = toml.rust {
+            config.download_rustc_commit =
+                config.download_ci_rustc_commit(rust.download_rustc.clone());
+
+            if config.download_rustc_commit.is_some() {
+                check_incompatible_options_for_ci_rustc(&rust);
+            }
+
             let Rust {
                 optimize: optimize_toml,
                 debug: debug_toml,
@@ -1617,7 +1624,7 @@ impl Config {
                 new_symbol_mangling,
                 profile_generate,
                 profile_use,
-                download_rustc,
+                download_rustc: _,
                 lto,
                 validate_mir_opts,
                 frame_pointers,
@@ -1627,11 +1634,7 @@ impl Config {
             } = rust;
 
             is_user_configured_rust_channel = channel.is_some();
-            set(&mut config.channel, channel);
-
-            config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc);
-
-            // FIXME: handle download-rustc incompatible options.
+            set(&mut config.channel, channel.clone());
 
             debug = debug_toml;
             debug_assertions = debug_assertions_toml;
@@ -2163,7 +2166,7 @@ impl Config {
 
         let mut git = helpers::git(Some(&self.src));
         git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap()));
-        output(&mut git.command)
+        output(git.as_command_mut())
     }
 
     /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
@@ -2466,22 +2469,14 @@ impl Config {
             }
         };
 
-        // Handle running from a directory other than the top level
-        let top_level = output(
-            &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command,
-        );
-        let top_level = top_level.trim_end();
-        let compiler = format!("{top_level}/compiler/");
-        let library = format!("{top_level}/library/");
-
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let merge_base = output(
-            &mut helpers::git(Some(&self.src))
+            helpers::git(Some(&self.src))
                 .arg("rev-list")
                 .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
                 .args(["-n1", "--first-parent", "HEAD"])
-                .command,
+                .as_command_mut(),
         );
         let commit = merge_base.trim_end();
         if commit.is_empty() {
@@ -2494,8 +2489,10 @@ impl Config {
 
         // Warn if there were changes to the compiler or standard library since the ancestor commit.
         let has_changes = !t!(helpers::git(Some(&self.src))
-            .args(["diff-index", "--quiet", commit, "--", &compiler, &library])
-            .command
+            .args(["diff-index", "--quiet", commit])
+            .arg("--")
+            .args([self.src.join("compiler"), self.src.join("library")])
+            .as_command_mut()
             .status())
         .success();
         if has_changes {
@@ -2566,20 +2563,14 @@ impl Config {
         option_name: &str,
         if_unchanged: bool,
     ) -> Option<String> {
-        // Handle running from a directory other than the top level
-        let top_level = output(
-            &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command,
-        );
-        let top_level = top_level.trim_end();
-
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let merge_base = output(
-            &mut helpers::git(Some(&self.src))
+            helpers::git(Some(&self.src))
                 .arg("rev-list")
                 .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
                 .args(["-n1", "--first-parent", "HEAD"])
-                .command,
+                .as_command_mut(),
         );
         let commit = merge_base.trim_end();
         if commit.is_empty() {
@@ -2594,11 +2585,14 @@ impl Config {
         let mut git = helpers::git(Some(&self.src));
         git.args(["diff-index", "--quiet", commit, "--"]);
 
+        // Handle running from a directory other than the top level
+        let top_level = &self.src;
+
         for path in modified_paths {
-            git.arg(format!("{top_level}/{path}"));
+            git.arg(top_level.join(path));
         }
 
-        let has_changes = !t!(git.command.status()).success();
+        let has_changes = !t!(git.as_command_mut().status()).success();
         if has_changes {
             if if_unchanged {
                 if self.verbose > 0 {
@@ -2618,6 +2612,113 @@ impl Config {
     }
 }
 
+/// Checks the CI rustc incompatible options by destructuring the `Rust` instance
+/// and makes sure that no rust options from config.toml are missed.
+fn check_incompatible_options_for_ci_rustc(rust: &Rust) {
+    macro_rules! err {
+        ($name:expr) => {
+            assert!(
+                $name.is_none(),
+                "ERROR: Setting `rust.{}` is incompatible with `rust.download-rustc`.",
+                stringify!($name).replace("_", "-")
+            );
+        };
+    }
+
+    macro_rules! warn {
+        ($name:expr) => {
+            if $name.is_some() {
+                println!(
+                    "WARNING: `rust.{}` has no effect with `rust.download-rustc`.",
+                    stringify!($name).replace("_", "-")
+                );
+            }
+        };
+    }
+
+    let Rust {
+        // Following options are the CI rustc incompatible ones.
+        optimize,
+        debug_logging,
+        debuginfo_level_rustc,
+        llvm_tools,
+        llvm_bitcode_linker,
+        lto,
+        stack_protector,
+        strip,
+        lld_mode,
+        jemalloc,
+        rpath,
+        channel,
+        description,
+        incremental,
+        default_linker,
+
+        // Rest of the options can simply be ignored.
+        debug: _,
+        codegen_units: _,
+        codegen_units_std: _,
+        debug_assertions: _,
+        debug_assertions_std: _,
+        overflow_checks: _,
+        overflow_checks_std: _,
+        debuginfo_level: _,
+        debuginfo_level_std: _,
+        debuginfo_level_tools: _,
+        debuginfo_level_tests: _,
+        split_debuginfo: _,
+        backtrace: _,
+        parallel_compiler: _,
+        musl_root: _,
+        verbose_tests: _,
+        optimize_tests: _,
+        codegen_tests: _,
+        omit_git_hash: _,
+        dist_src: _,
+        save_toolstates: _,
+        codegen_backends: _,
+        lld: _,
+        deny_warnings: _,
+        backtrace_on_ice: _,
+        verify_llvm_ir: _,
+        thin_lto_import_instr_limit: _,
+        remap_debuginfo: _,
+        test_compare_mode: _,
+        llvm_libunwind: _,
+        control_flow_guard: _,
+        ehcont_guard: _,
+        new_symbol_mangling: _,
+        profile_generate: _,
+        profile_use: _,
+        download_rustc: _,
+        validate_mir_opts: _,
+        frame_pointers: _,
+    } = rust;
+
+    // There are two kinds of checks for CI rustc incompatible options:
+    //    1. Checking an option that may change the compiler behaviour/output.
+    //    2. Checking an option that have no effect on the compiler behaviour/output.
+    //
+    // If the option belongs to the first category, we call `err` macro for a hard error;
+    // otherwise, we just print a warning with `warn` macro.
+    err!(optimize);
+    err!(debug_logging);
+    err!(debuginfo_level_rustc);
+    err!(default_linker);
+    err!(rpath);
+    err!(strip);
+    err!(stack_protector);
+    err!(lld_mode);
+    err!(llvm_tools);
+    err!(llvm_bitcode_linker);
+    err!(jemalloc);
+    err!(lto);
+
+    warn!(channel);
+    warn!(description);
+    warn!(incremental);
+}
+
 fn set<T>(field: &mut T, val: Option<T>) {
     if let Some(v) = val {
         *field = v;
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index aeb608a9ea2..19f752da81c 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -1,4 +1,4 @@
-//! Command-line interface of the rustbuild build system.
+//! Command-line interface of the bootstrap build system.
 //!
 //! This module implements the command-line parsing of the build system which
 //! has various flags to configure how it's run.
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index a7f4bb0cf14..d01a910e815 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -702,9 +702,13 @@ download-rustc = false
             // time `rustc_llvm` build script ran. However, the timestamps of the
             // files in the tarball are in the past, so it doesn't trigger a
             // rebuild.
-            let now = filetime::FileTime::from_system_time(std::time::SystemTime::now());
+            let now = std::time::SystemTime::now();
+            let file_times = fs::FileTimes::new().set_accessed(now).set_modified(now);
+
             let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build));
-            t!(filetime::set_file_times(llvm_config, now, now));
+            let llvm_config_file = t!(File::open(llvm_config));
+
+            t!(llvm_config_file.set_times(file_times));
 
             if self.should_fix_bins_and_dylibs() {
                 let llvm_lib = llvm_root.join("lib");
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 9995da3a1e5..2be819d52ea 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -1,4 +1,4 @@
-//! Sanity checking performed by rustbuild before actually executing anything.
+//! Sanity checking performed by bootstrap before actually executing anything.
 //!
 //! This module contains the implementation of ensuring that the build
 //! environment looks reasonable before progressing. This will verify that
@@ -209,7 +209,7 @@ than building it.
 
     #[cfg(not(feature = "bootstrap-self-test"))]
     let stage0_supported_target_list: HashSet<String> = crate::utils::helpers::output(
-        &mut command(&build.config.initial_rustc).args(["--print", "target-list"]).command,
+        command(&build.config.initial_rustc).args(["--print", "target-list"]).as_command_mut(),
     )
     .lines()
     .map(|s| s.to_string())
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index f16afb29796..db1fa05a82c 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -1,9 +1,9 @@
-//! Implementation of rustbuild, the Rust build system.
+//! Implementation of bootstrap, the Rust build system.
 //!
 //! This module, and its descendants, are the implementation of the Rust build
 //! system. Most of this build system is backed by Cargo but the outer layer
 //! here serves as the ability to orchestrate calling Cargo, sequencing Cargo
-//! builds, building artifacts like LLVM, etc. The goals of rustbuild are:
+//! builds, building artifacts like LLVM, etc. The goals of bootstrap are:
 //!
 //! * To be an easily understandable, easily extensible, and maintainable build
 //!   system.
@@ -23,21 +23,20 @@ use std::fmt::Display;
 use std::fs::{self, File};
 use std::io;
 use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
+use std::process::Command;
 use std::str;
 use std::sync::OnceLock;
 use std::time::SystemTime;
 
 use build_helper::ci::{gha, CiEnv};
 use build_helper::exit;
-use filetime::FileTime;
 use sha2::digest::Digest;
 use termcolor::{ColorChoice, StandardStream, WriteColor};
 use utils::channel::GitInfo;
 use utils::helpers::hex_encode;
 
 use crate::core::builder;
-use crate::core::builder::Kind;
+use crate::core::builder::{Builder, Kind};
 use crate::core::config::{flags, LldMode};
 use crate::core::config::{DryRun, Target};
 use crate::core::config::{LlvmLibunwind, TargetSelection};
@@ -490,15 +489,29 @@ impl Build {
             return;
         }
 
-        let submodule_git = || helpers::git(Some(&absolute_path));
+        // Submodule updating actually happens during in the dry run mode. We need to make sure that
+        // all the git commands below are actually executed, because some follow-up code
+        // in bootstrap might depend on the submodules being checked out. Furthermore, not all
+        // the command executions below work with an empty output (produced during dry run).
+        // Therefore, all commands below are marked with `run_always()`, so that they also run in
+        // dry run mode.
+        let submodule_git = || {
+            let mut cmd = helpers::git(Some(&absolute_path)).capture_stdout();
+            cmd.run_always();
+            cmd
+        };
 
         // Determine commit checked out in submodule.
-        let checked_out_hash = output(&mut submodule_git().args(["rev-parse", "HEAD"]).command);
+        let checked_out_hash = submodule_git().args(["rev-parse", "HEAD"]).run(self).stdout();
         let checked_out_hash = checked_out_hash.trim_end();
         // Determine commit that the submodule *should* have.
-        let recorded = output(
-            &mut helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path).command,
-        );
+        let recorded = helpers::git(Some(&self.src))
+            .capture_stdout()
+            .run_always()
+            .args(["ls-tree", "HEAD"])
+            .arg(relative_path)
+            .run(self)
+            .stdout();
         let actual_hash = recorded
             .split_whitespace()
             .nth(2)
@@ -511,6 +524,7 @@ impl Build {
 
         println!("Updating submodule {}", relative_path.display());
         helpers::git(Some(&self.src))
+            .run_always()
             .args(["submodule", "-q", "sync"])
             .arg(relative_path)
             .run(self);
@@ -519,21 +533,16 @@ impl Build {
         let update = |progress: bool| {
             // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
             // even though that has no relation to the upstream for the submodule.
-            let current_branch = {
-                let output = helpers::git(Some(&self.src))
-                    .args(["symbolic-ref", "--short", "HEAD"])
-                    .command
-                    .stderr(Stdio::inherit())
-                    .output();
-                let output = t!(output);
-                if output.status.success() {
-                    Some(String::from_utf8(output.stdout).unwrap().trim().to_owned())
-                } else {
-                    None
-                }
-            };
+            let current_branch = helpers::git(Some(&self.src))
+                .capture_stdout()
+                .run_always()
+                .args(["symbolic-ref", "--short", "HEAD"])
+                .run(self)
+                .stdout_if_ok()
+                .map(|s| s.trim().to_owned());
 
-            let mut git = helpers::git(Some(&self.src));
+            let mut git = helpers::git(Some(&self.src)).allow_failure();
+            git.run_always();
             if let Some(branch) = current_branch {
                 // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
                 // This syntax isn't accepted by `branch.{branch}`. Strip it.
@@ -547,8 +556,7 @@ impl Build {
             git.arg(relative_path);
             git
         };
-        // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
-        if !update(true).command.status().map_or(false, |status| status.success()) {
+        if !update(true).run(self).is_success() {
             update(false).run(self);
         }
 
@@ -934,17 +942,26 @@ impl Build {
 
     /// Execute a command and return its output.
     /// This method should be used for all command executions in bootstrap.
+    #[track_caller]
     fn run(&self, command: &mut BootstrapCommand) -> CommandOutput {
+        command.mark_as_executed();
         if self.config.dry_run() && !command.run_always {
             return CommandOutput::default();
         }
 
-        self.verbose(|| println!("running: {command:?}"));
+        let created_at = command.get_created_location();
+        let executed_at = std::panic::Location::caller();
+
+        self.verbose(|| {
+            println!("running: {command:?} (created at {created_at}, executed at {executed_at})")
+        });
 
-        command.command.stdout(command.stdout.stdio());
-        command.command.stderr(command.stderr.stdio());
+        let stdout = command.stdout.stdio();
+        command.as_command_mut().stdout(stdout);
+        let stderr = command.stderr.stdio();
+        command.as_command_mut().stderr(stderr);
 
-        let output = command.command.output();
+        let output = command.as_command_mut().output();
 
         use std::fmt::Write;
 
@@ -956,8 +973,11 @@ impl Build {
             Ok(output) => {
                 writeln!(
                     message,
-                    "\n\nCommand {command:?} did not execute successfully.\
-            \nExpected success, got: {}",
+                    r#"
+Command {command:?} did not execute successfully.
+Expected success, got {}
+Created at: {created_at}
+Executed at: {executed_at}"#,
                     output.status,
                 )
                 .unwrap();
@@ -1693,9 +1713,13 @@ impl Build {
                 panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
             }
             t!(fs::set_permissions(dst, metadata.permissions()));
-            let atime = FileTime::from_last_access_time(&metadata);
-            let mtime = FileTime::from_last_modification_time(&metadata);
-            t!(filetime::set_file_times(dst, atime, mtime));
+
+            let file_times = fs::FileTimes::new()
+                .set_accessed(t!(metadata.accessed()))
+                .set_modified(t!(metadata.modified()));
+
+            let dst_file = t!(fs::File::open(dst));
+            t!(dst_file.set_times(file_times));
         }
     }
 
@@ -1928,22 +1952,28 @@ fn envify(s: &str) -> String {
 ///
 /// In case of errors during `git` command execution (e.g., in tarball sources), default values
 /// are used to prevent panics.
-pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String {
+pub fn generate_smart_stamp_hash(
+    builder: &Builder<'_>,
+    dir: &Path,
+    additional_input: &str,
+) -> String {
     let diff = helpers::git(Some(dir))
+        .capture_stdout()
+        .allow_failure()
         .arg("diff")
-        .command
-        .output()
-        .map(|o| String::from_utf8(o.stdout).unwrap_or_default())
+        .run(builder)
+        .stdout_if_ok()
         .unwrap_or_default();
 
     let status = helpers::git(Some(dir))
+        .capture_stdout()
+        .allow_failure()
         .arg("status")
         .arg("--porcelain")
         .arg("-z")
         .arg("--untracked-files=normal")
-        .command
-        .output()
-        .map(|o| String::from_utf8(o.stdout).unwrap_or_default())
+        .run(builder)
+        .stdout_if_ok()
         .unwrap_or_default();
 
     let mut hasher = sha2::Sha256::new();
diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs
index 2ca86bdb0ed..f8bcb584991 100644
--- a/src/bootstrap/src/utils/channel.rs
+++ b/src/bootstrap/src/utils/channel.rs
@@ -45,7 +45,7 @@ impl GitInfo {
         }
 
         // Make sure git commands work
-        match helpers::git(Some(dir)).arg("rev-parse").command.output() {
+        match helpers::git(Some(dir)).arg("rev-parse").as_command_mut().output() {
             Ok(ref out) if out.status.success() => {}
             _ => return GitInfo::Absent,
         }
@@ -58,16 +58,17 @@ impl GitInfo {
 
         // Ok, let's scrape some info
         let ver_date = output(
-            &mut helpers::git(Some(dir))
+            helpers::git(Some(dir))
                 .arg("log")
                 .arg("-1")
                 .arg("--date=short")
                 .arg("--pretty=format:%cd")
-                .command,
+                .as_command_mut(),
         );
-        let ver_hash = output(&mut helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").command);
+        let ver_hash =
+            output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").as_command_mut());
         let short_ver_hash = output(
-            &mut helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").command,
+            helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").as_command_mut(),
         );
         GitInfo::Present(Some(Info {
             commit_date: ver_date.trim().to_string(),
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index ba963f52dc2..a60c0084f3d 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -1,5 +1,8 @@
 use crate::Build;
+use build_helper::ci::CiEnv;
+use build_helper::drop_bomb::DropBomb;
 use std::ffi::OsStr;
+use std::fmt::{Debug, Formatter};
 use std::path::Path;
 use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio};
 
@@ -53,17 +56,20 @@ impl OutputMode {
 ///
 /// [allow_failure]: BootstrapCommand::allow_failure
 /// [delay_failure]: BootstrapCommand::delay_failure
-#[derive(Debug)]
 pub struct BootstrapCommand {
-    pub command: Command,
+    command: Command,
     pub failure_behavior: BehaviorOnFailure,
     pub stdout: OutputMode,
     pub stderr: OutputMode,
     // Run the command even during dry run
     pub run_always: bool,
+    // This field makes sure that each command is executed (or disarmed) before it is dropped,
+    // to avoid forgetting to execute a command.
+    drop_bomb: DropBomb,
 }
 
 impl BootstrapCommand {
+    #[track_caller]
     pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
         Command::new(program).into()
     }
@@ -142,19 +148,67 @@ impl BootstrapCommand {
     }
 
     /// Run the command, returning its output.
+    #[track_caller]
     pub fn run(&mut self, builder: &Build) -> CommandOutput {
         builder.run(self)
     }
+
+    /// Provides access to the stdlib Command inside.
+    /// FIXME: This function should be eventually removed from bootstrap.
+    pub fn as_command_mut(&mut self) -> &mut Command {
+        // We don't know what will happen with the returned command, so we need to mark this
+        // command as executed proactively.
+        self.mark_as_executed();
+        &mut self.command
+    }
+
+    /// Mark the command as being executed, disarming the drop bomb.
+    /// If this method is not called before the command is dropped, its drop will panic.
+    pub fn mark_as_executed(&mut self) {
+        self.drop_bomb.defuse();
+    }
+
+    /// Returns the source code location where this command was created.
+    pub fn get_created_location(&self) -> std::panic::Location<'static> {
+        self.drop_bomb.get_created_location()
+    }
+
+    /// If in a CI environment, forces the command to run with colors.
+    pub fn force_coloring_in_ci(&mut self, ci_env: CiEnv) {
+        if ci_env != CiEnv::None {
+            // Due to use of stamp/docker, the output stream of bootstrap is not
+            // a TTY in CI, so coloring is by-default turned off.
+            // The explicit `TERM=xterm` environment is needed for
+            // `--color always` to actually work. This env var was lost when
+            // compiling through the Makefile. Very strange.
+            self.env("TERM", "xterm").args(["--color", "always"]);
+        }
+    }
+}
+
+impl Debug for BootstrapCommand {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{:?}", self.command)?;
+        write!(
+            f,
+            " (failure_mode={:?}, stdout_mode={:?}, stderr_mode={:?})",
+            self.failure_behavior, self.stdout, self.stderr
+        )
+    }
 }
 
 impl From<Command> for BootstrapCommand {
+    #[track_caller]
     fn from(command: Command) -> Self {
+        let program = command.get_program().to_owned();
+
         Self {
             command,
             failure_behavior: BehaviorOnFailure::Exit,
             stdout: OutputMode::Print,
             stderr: OutputMode::Print,
             run_always: false,
+            drop_bomb: DropBomb::arm(program),
         }
     }
 }
@@ -169,6 +223,7 @@ enum CommandStatus {
 
 /// Create a new BootstrapCommand. This is a helper function to make command creation
 /// shorter than `BootstrapCommand::new`.
+#[track_caller]
 #[must_use]
 pub fn command<S: AsRef<OsStr>>(program: S) -> BootstrapCommand {
     BootstrapCommand::new(program)
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 5dd3ba96786..3c82fa189be 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -1,4 +1,4 @@
-//! Various utility functions used throughout rustbuild.
+//! Various utility functions used throughout bootstrap.
 //!
 //! Simple things like testing the various filesystem operations here and there,
 //! not a lot of interesting happenings here unfortunately.
@@ -244,7 +244,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
 
 // FIXME: get rid of this function
 pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool {
-    let status = match cmd.command.status() {
+    let status = match cmd.as_command_mut().status() {
         Ok(status) => status,
         Err(e) => {
             println!("failed to execute command: {cmd:?}\nERROR: {e}");
@@ -338,13 +338,13 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
 /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource
 /// directory to the linker flags, otherwise there will be linker errors about the profiler runtime
 /// missing. This function returns the path to that directory.
-pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf {
+pub fn get_clang_cl_resource_dir(builder: &Builder<'_>, clang_cl_path: &str) -> PathBuf {
     // Similar to how LLVM does it, to find clang's library runtime directory:
     // - we ask `clang-cl` to locate the `clang_rt.builtins` lib.
-    let mut builtins_locator = Command::new(clang_cl_path);
+    let mut builtins_locator = command(clang_cl_path);
     builtins_locator.args(["/clang:-print-libgcc-file-name", "/clang:--rtlib=compiler-rt"]);
 
-    let clang_rt_builtins = output(&mut builtins_locator);
+    let clang_rt_builtins = builtins_locator.capture_stdout().run(builder).stdout();
     let clang_rt_builtins = Path::new(clang_rt_builtins.trim());
     assert!(
         clang_rt_builtins.exists(),
@@ -501,6 +501,7 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String {
 /// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every
 /// git command creation, which is painful to ensure that the required change is applied
 /// on each one of them correctly.
+#[track_caller]
 pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
     let mut git = command("git");
 
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 2e99bc68a8b..a3d0d36e754 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -33,6 +33,7 @@ pub(crate) fn try_run_tests(
     stream: bool,
 ) -> bool {
     if builder.config.dry_run() {
+        cmd.mark_as_executed();
         return true;
     }
 
@@ -50,7 +51,7 @@ pub(crate) fn try_run_tests(
 }
 
 fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool {
-    let cmd = &mut cmd.command;
+    let cmd = cmd.as_command_mut();
     cmd.stdout(Stdio::piped());
 
     builder.verbose(|| println!("running: {cmd:?}"));
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 4f0104e4bba..9378c35127f 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -369,13 +369,13 @@ impl<'a> Tarball<'a> {
         // gets the same timestamp.
         if self.builder.rust_info().is_managed_git_subrepository() {
             // %ct means committer date
-            let timestamp = helpers::output(
-                &mut helpers::git(Some(&self.builder.src))
-                    .arg("log")
-                    .arg("-1")
-                    .arg("--format=%ct")
-                    .command,
-            );
+            let timestamp = helpers::git(Some(&self.builder.src))
+                .capture_stdout()
+                .arg("log")
+                .arg("-1")
+                .arg("--format=%ct")
+                .run(self.builder)
+                .stdout();
             cmd.args(["--override-file-mtime", timestamp.trim()]);
         }
 
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile
index 426e601f5d3..4d9334dde8c 100644
--- a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile
@@ -11,6 +11,7 @@ RUN sh /scripts/rustbuild-setup.sh
 WORKDIR /tmp
 
 COPY scripts/crosstool-ng-build.sh /scripts/
+COPY host-x86_64/dist-riscv64-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig
 RUN /scripts/crosstool-ng-build.sh
 
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch
new file mode 100644
index 00000000000..f688eaf8029
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0001-divdi3-div-zero.patch
@@ -0,0 +1,37 @@
+From 4013baf99c38f7bca06a51f8301e8fb195ccfa33 Mon Sep 17 00:00:00 2001
+From: Jim Wilson <jimw@sifive.com>
+Date: Tue, 2 Jun 2020 11:19:39 -0700
+Subject: [PATCH] RISC-V: Make __divdi3 handle div by zero same as hardware.
+
+The ISA manual specifies that divide by zero always returns -1 as the result.
+We were failing to do that when the dividend was negative.
+
+Original patch from Virginie Moser.
+
+	libgcc/
+	* config/riscv/div.S (__divdi3): For negative arguments, change bgez
+	to bgtz.
+---
+ libgcc/config/riscv/div.S | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S
+index 151f8e273ac77..17234324c1e41 100644
+--- a/libgcc/config/riscv/div.S
++++ b/libgcc/config/riscv/div.S
+@@ -107,10 +107,12 @@ FUNC_END (__umoddi3)
+   /* Handle negative arguments to __divdi3.  */
+ .L10:
+   neg   a0, a0
+-  bgez  a1, .L12      /* Compute __udivdi3(-a0, a1), then negate the result.  */
++  /* Zero is handled as a negative so that the result will not be inverted.  */
++  bgtz  a1, .L12     /* Compute __udivdi3(-a0, a1), then negate the result.  */
++
+   neg   a1, a1
+-  j     __udivdi3     /* Compute __udivdi3(-a0, -a1).  */
+-.L11:                 /* Compute __udivdi3(a0, -a1), then negate the result.  */
++  j     __udivdi3    /* Compute __udivdi3(-a0, -a1).  */
++.L11:                /* Compute __udivdi3(a0, -a1), then negate the result.  */
+   neg   a1, a1
+ .L12:
+   move  t0, ra
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch
new file mode 100644
index 00000000000..7ae4469428b
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/gcc/8.5.0/0002-hidden-jump-target.patch
@@ -0,0 +1,117 @@
+From 45116f342057b7facecd3d05c2091ce3a77eda59 Mon Sep 17 00:00:00 2001
+From: Nelson Chu <nelson.chu@sifive.com>
+Date: Mon, 29 Nov 2021 04:48:20 -0800
+Subject: [PATCH] RISC-V: jal cannot refer to a default visibility symbol for
+ shared object.
+
+This is the original binutils bugzilla report,
+https://sourceware.org/bugzilla/show_bug.cgi?id=28509
+
+And this is the first version of the proposed binutils patch,
+https://sourceware.org/pipermail/binutils/2021-November/118398.html
+
+After applying the binutils patch, I get the the unexpected error when
+building libgcc,
+
+/scratch/nelsonc/riscv-gnu-toolchain/riscv-gcc/libgcc/config/riscv/div.S:42:
+/scratch/nelsonc/build-upstream/rv64gc-linux/build-install/riscv64-unknown-linux-gnu/bin/ld: relocation R_RISCV_JAL against `__udivdi3' which may bind externally can not be used when making a shared object; recompile with -fPIC
+
+Therefore, this patch add an extra hidden alias symbol for __udivdi3, and
+then use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead.
+The solution is similar to glibc as follows,
+https://sourceware.org/git/?p=glibc.git;a=commit;h=68389203832ab39dd0dbaabbc4059e7fff51c29b
+
+libgcc/ChangeLog:
+
+	* config/riscv/div.S: Add the hidden alias symbol for __udivdi3, and
+	then use HIDDEN_JUMPTARGET to target it since it is non-preemptible.
+	* config/riscv/riscv-asm.h: Added new macros HIDDEN_JUMPTARGET and
+	HIDDEN_DEF.
+---
+ libgcc/config/riscv/div.S       | 15 ++++++++-------
+ libgcc/config/riscv/riscv-asm.h |  6 ++++++
+ 2 files changed, 14 insertions(+), 7 deletions(-)
+
+diff --git a/libgcc/config/riscv/div.S b/libgcc/config/riscv/div.S
+index c9bd7879c1e36..723c3b82e48c6 100644
+--- a/libgcc/config/riscv/div.S
++++ b/libgcc/config/riscv/div.S
+@@ -40,7 +40,7 @@ FUNC_BEGIN (__udivsi3)
+   sll    a0, a0, 32
+   sll    a1, a1, 32
+   move   t0, ra
+-  jal    __udivdi3
++  jal    HIDDEN_JUMPTARGET(__udivdi3)
+   sext.w a0, a0
+   jr     t0
+ FUNC_END (__udivsi3)
+@@ -52,7 +52,7 @@ FUNC_BEGIN (__umodsi3)
+   srl    a0, a0, 32
+   srl    a1, a1, 32
+   move   t0, ra
+-  jal    __udivdi3
++  jal    HIDDEN_JUMPTARGET(__udivdi3)
+   sext.w a0, a1
+   jr     t0
+ FUNC_END (__umodsi3)
+@@ -95,11 +95,12 @@ FUNC_BEGIN (__udivdi3)
+ .L5:
+   ret
+ FUNC_END (__udivdi3)
++HIDDEN_DEF (__udivdi3)
+ 
+ FUNC_BEGIN (__umoddi3)
+   /* Call __udivdi3(a0, a1), then return the remainder, which is in a1.  */
+   move  t0, ra
+-  jal   __udivdi3
++  jal   HIDDEN_JUMPTARGET(__udivdi3)
+   move  a0, a1
+   jr    t0
+ FUNC_END (__umoddi3)
+@@ -111,12 +112,12 @@ FUNC_END (__umoddi3)
+   bgtz  a1, .L12     /* Compute __udivdi3(-a0, a1), then negate the result.  */
+ 
+   neg   a1, a1
+-  j     __udivdi3    /* Compute __udivdi3(-a0, -a1).  */
++  j     HIDDEN_JUMPTARGET(__udivdi3)     /* Compute __udivdi3(-a0, -a1).  */
+ .L11:                /* Compute __udivdi3(a0, -a1), then negate the result.  */
+   neg   a1, a1
+ .L12:
+   move  t0, ra
+-  jal   __udivdi3
++  jal   HIDDEN_JUMPTARGET(__udivdi3)
+   neg   a0, a0
+   jr    t0
+ FUNC_END (__divdi3)
+@@ -126,7 +127,7 @@ FUNC_BEGIN (__moddi3)
+   bltz   a1, .L31
+   bltz   a0, .L32
+ .L30:
+-  jal    __udivdi3    /* The dividend is not negative.  */
++  jal    HIDDEN_JUMPTARGET(__udivdi3)    /* The dividend is not negative.  */
+   move   a0, a1
+   jr     t0
+ .L31:
+@@ -134,7 +135,7 @@ FUNC_BEGIN (__moddi3)
+   bgez   a0, .L30
+ .L32:
+   neg    a0, a0
+-  jal    __udivdi3    /* The dividend is hella negative.  */
++  jal    HIDDEN_JUMPTARGET(__udivdi3)    /* The dividend is hella negative.  */
+   neg    a0, a1
+   jr     t0
+ FUNC_END (__moddi3)
+diff --git a/libgcc/config/riscv/riscv-asm.h b/libgcc/config/riscv/riscv-asm.h
+index 8550707a4a26a..96dd85b0df2e5 100644
+--- a/libgcc/config/riscv/riscv-asm.h
++++ b/libgcc/config/riscv/riscv-asm.h
+@@ -33,3 +33,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ #define FUNC_ALIAS(X,Y)		\
+ 	.globl X;		\
+ 	X = Y
++
++#define CONCAT1(a, b)		CONCAT2(a, b)
++#define CONCAT2(a, b)		a ## b
++#define HIDDEN_JUMPTARGET(X)	CONCAT1(__hidden_, X)
++#define HIDDEN_DEF(X)		FUNC_ALIAS(HIDDEN_JUMPTARGET(X), X);     \
++				.hidden HIDDEN_JUMPTARGET(X)
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch
new file mode 100644
index 00000000000..d267b961d34
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/patches/glibc/2.29/0001-hidden-jump-target.patch
@@ -0,0 +1,58 @@
+From 68389203832ab39dd0dbaabbc4059e7fff51c29b Mon Sep 17 00:00:00 2001
+From: Fangrui Song <maskray@google.com>
+Date: Thu, 28 Oct 2021 11:39:49 -0700
+Subject: [PATCH] riscv: Fix incorrect jal with HIDDEN_JUMPTARGET
+
+A non-local STV_DEFAULT defined symbol is by default preemptible in a
+shared object. j/jal cannot target a preemptible symbol. On other
+architectures, such a jump instruction either causes PLT [BZ #18822], or
+if short-ranged, sometimes rejected by the linker (but not by GNU ld's
+riscv port [ld PR/28509]).
+
+Use HIDDEN_JUMPTARGET to target a non-preemptible symbol instead.
+
+With this patch, ld.so and libc.so can be linked with LLD if source
+files are compiled/assembled with -mno-relax/-Wa,-mno-relax.
+
+Acked-by: Palmer Dabbelt <palmer@dabbelt.com>
+Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+---
+ sysdeps/riscv/setjmp.S                     | 2 +-
+ sysdeps/unix/sysv/linux/riscv/setcontext.S | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/sysdeps/riscv/setjmp.S b/sysdeps/riscv/setjmp.S
+index 0b92016b311..bec7ff80f49 100644
+--- a/sysdeps/riscv/setjmp.S
++++ b/sysdeps/riscv/setjmp.S
+@@ -21,7 +21,7 @@
+ 
+ ENTRY (_setjmp)
+   li	a1, 0
+-  j	__sigsetjmp
++  j	HIDDEN_JUMPTARGET (__sigsetjmp)
+ END (_setjmp)
+ ENTRY (setjmp)
+   li	a1, 1
+diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S
+index 9510518750a..e44a68aad47 100644
+--- a/sysdeps/unix/sysv/linux/riscv/setcontext.S
++++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S
+@@ -95,6 +95,7 @@ LEAF (__setcontext)
+ 99:	j	__syscall_error
+ 
+ END (__setcontext)
++libc_hidden_def (__setcontext)
+ weak_alias (__setcontext, setcontext)
+ 
+ LEAF (__start_context)
+@@ -108,7 +109,7 @@ LEAF (__start_context)
+ 	/* Invoke subsequent context if present, else exit(0).  */
+ 	mv	a0, s2
+ 	beqz	s2, 1f
+-	jal	__setcontext
+-1:	j	exit
++	jal	HIDDEN_JUMPTARGET (__setcontext)
++1:	j	HIDDEN_JUMPTARGET (exit)
+ 
+ END (__start_context)
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig
index 470cef1a84e..f7c93a9d5fc 100644
--- a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig
+++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig
@@ -3,6 +3,8 @@ CT_EXPERIMENTAL=y
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
 CT_USE_MIRROR=y
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_PATCH_BUNDLED_LOCAL=y
+CT_LOCAL_PATCH_DIR="/tmp/patches"
 CT_ARCH_RISCV=y
 # CT_DEMULTILIB is not set
 CT_ARCH_USE_MMU=y
@@ -10,7 +12,7 @@ CT_ARCH_64=y
 CT_ARCH_ARCH="rv64gc"
 CT_KERNEL_LINUX=y
 CT_LINUX_V_4_20=y
-CT_BINUTILS_V_2_36=y
+CT_BINUTILS_V_2_40=y
 CT_GLIBC_V_2_29=y
 CT_GCC_V_8=y
 CT_CC_LANG_CXX=y
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index 24b9904d65c..6103aa61248 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -40,7 +40,7 @@ if isMacOS; then
     # our own clang can figure out the correct include path on its own.
     ciCommandSetEnv SDKROOT "$(xcrun --sdk macosx --show-sdk-path)"
 
-    # Configure `AR` specifically so rustbuild doesn't try to infer it as
+    # Configure `AR` specifically so bootstrap doesn't try to infer it as
     # `clang-ar` by accident.
     ciCommandSetEnv AR "ar"
 elif isWindows && ! isKnownToBeMingwBuild; then
diff --git a/src/doc/book b/src/doc/book
-Subproject f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc6
+Subproject 67fa536768013d9d5a13f3a06790521d511ef71
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 941db8b3df45fd46cd87b50a5c86714b91dcde9
+Subproject 5454de3d12b9ccc6375b629cf7ccda8264640aa
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject b10c6acaf0f43481f6600e95d4b5013446e29f7
+Subproject 019f3928d8b939ec71b63722dcc2e4633015644
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 1ae3deebc3ac16e276b6558e01420f8e605def0
+Subproject e2f0bdc4031866734661dcdb548184bde1450ba
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 658c6c27cb975b92227936024816986c2d3716f
+Subproject 89aecb6951b77bc746da73df8c9f2b2ceaad494
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject d6e3a32a557db5902e714604def8015d6bb7e0f
+Subproject 0c4d55cb59fe440d1a630e4e5774d043968edb3
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index f5cd4bd217a..370dbed50fa 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -41,10 +41,10 @@ target | notes
 `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+)
 `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
 
-[^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. See [issue #114479][x86-32-float-issue].
+[^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue].
 
 [77071]: https://github.com/rust-lang/rust/issues/77071
-[x86-32-float-issue]: https://github.com/rust-lang/rust/issues/114479
+[x86-32-float-return-issue]: https://github.com/rust-lang/rust/issues/115567
 
 ## Tier 1
 
@@ -209,6 +209,8 @@ target | std | notes
 
 [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue].
 
+[x86-32-float-issue]: https://github.com/rust-lang/rust/issues/114479
+
 [wasi-rename]: https://github.com/rust-lang/compiler-team/issues/607
 
 [Fortanix ABI]: https://edp.fortanix.com/
diff --git a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md
index 97b5827c144..33e1c44e6d3 100644
--- a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md
+++ b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md
@@ -46,7 +46,7 @@ on how to setup a development and runtime environment.
 
 As a tier 2 target, the target is built by the Rust project.
 
-You can configure rustbuild like so:
+You can configure bootstrap like so:
 
 ```toml
 [build]
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index aa596897fc4..a0e28d2f55c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -228,8 +228,9 @@ fn clean_generic_bound<'tcx>(
 
             GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
         }
-        // FIXME(precise_capturing): Implement rustdoc support
-        hir::GenericBound::Use(..) => return None,
+        hir::GenericBound::Use(args, ..) => {
+            GenericBound::Use(args.iter().map(|arg| arg.name()).collect())
+        }
     })
 }
 
@@ -1051,12 +1052,12 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib
         for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() {
             match literal.kind {
                 ast::LitKind::Int(a, _) => {
-                    let gen = func.generics.params.remove(0);
+                    let param = func.generics.params.remove(0);
                     if let GenericParamDef {
                         name,
                         kind: GenericParamDefKind::Const { ty, .. },
                         ..
-                    } = gen
+                    } = param
                     {
                         func.decl
                             .inputs
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 58eef36677b..1b7d84add1f 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -79,7 +79,7 @@ pub(crate) fn merge_bounds(
     !bounds.iter_mut().any(|b| {
         let trait_ref = match *b {
             clean::GenericBound::TraitBound(ref mut tr, _) => tr,
-            clean::GenericBound::Outlives(..) => return false,
+            clean::GenericBound::Outlives(..) | clean::GenericBound::Use(_) => return false,
         };
         // If this QPath's trait `trait_did` is the same as, or a supertrait
         // of, the bound's trait `did` then we can keep going, otherwise
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index fe01d17b08a..a31adc9949a 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1244,6 +1244,8 @@ impl Eq for Attributes {}
 pub(crate) enum GenericBound {
     TraitBound(PolyTrait, hir::TraitBoundModifier),
     Outlives(Lifetime),
+    /// `use<'a, T>` precise-capturing bound syntax
+    Use(Vec<Symbol>),
 }
 
 impl GenericBound {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 4268fadd6c5..9b0b2571ec1 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -412,6 +412,20 @@ impl clean::GenericBound {
                 })?;
                 ty.print(cx).fmt(f)
             }
+            clean::GenericBound::Use(args) => {
+                if f.alternate() {
+                    f.write_str("use<")?;
+                } else {
+                    f.write_str("use&lt;")?;
+                }
+                for (i, arg) in args.iter().enumerate() {
+                    if i > 0 {
+                        write!(f, ", ")?;
+                    }
+                    arg.fmt(f)?;
+                }
+                if f.alternate() { f.write_str(">") } else { f.write_str("&gt;") }
+            }
         })
     }
 }
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index bc8bdffc331..66d3f0fd8ce 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -1051,7 +1051,7 @@ fn simplify_fn_type<'tcx, 'a>(
         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(|gen| match gen {
+            for ty in arg_generics.into_iter().filter_map(|param| match param {
                 clean::GenericArg::Type(ty) => Some(ty),
                 _ => None,
             }) {
@@ -1172,8 +1172,8 @@ fn simplify_fn_constraint<'tcx, 'a>(
 ) {
     let mut ty_constraints = Vec::new();
     let ty_constrained_assoc = RenderTypeId::AssociatedType(constraint.assoc.name);
-    for gen in &constraint.assoc.args {
-        match gen {
+    for param in &constraint.assoc.args {
+        match param {
             clean::GenericArg::Type(arg) => simplify_fn_type(
                 self_,
                 generics,
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 5111e363c52..4ab0df36708 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -542,6 +542,7 @@ impl FromWithTcx<clean::GenericBound> for GenericBound {
                 }
             }
             Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
+            Use(args) => GenericBound::Use(args.into_iter().map(|arg| arg.to_string()).collect()),
         }
     }
 }
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 89115d4d7d6..6fd23b60c8a 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 31;
+pub const FORMAT_VERSION: u32 = 32;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -538,6 +538,8 @@ pub enum GenericBound {
         modifier: TraitBoundModifier,
     },
     Outlives(String),
+    /// `use<'a, T>` precise-capturing bound syntax
+    Use(Vec<String>),
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs
index 09489b0d9b7..6d79c7c83ad 100644
--- a/src/tools/build_helper/src/ci.rs
+++ b/src/tools/build_helper/src/ci.rs
@@ -1,5 +1,3 @@
-use std::process::Command;
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum CiEnv {
     /// Not a CI environment.
@@ -21,18 +19,6 @@ impl CiEnv {
     pub fn is_ci() -> bool {
         Self::current() != CiEnv::None
     }
-
-    /// If in a CI environment, forces the command to run with colors.
-    pub fn force_coloring_in_ci(self, cmd: &mut Command) {
-        if self != CiEnv::None {
-            // Due to use of stamp/docker, the output stream of rustbuild is not
-            // a TTY in CI, so coloring is by-default turned off.
-            // The explicit `TERM=xterm` environment is needed for
-            // `--color always` to actually work. This env var was lost when
-            // compiling through the Makefile. Very strange.
-            cmd.env("TERM", "xterm").args(&["--color", "always"]);
-        }
-    }
 }
 
 pub mod gha {
diff --git a/src/tools/run-make-support/src/drop_bomb/mod.rs b/src/tools/build_helper/src/drop_bomb/mod.rs
index 2fc84892c1b..0a5bb04b55b 100644
--- a/src/tools/run-make-support/src/drop_bomb/mod.rs
+++ b/src/tools/build_helper/src/drop_bomb/mod.rs
@@ -12,27 +12,31 @@ use std::panic;
 mod tests;
 
 #[derive(Debug)]
-pub(crate) struct DropBomb {
+pub struct DropBomb {
     command: OsString,
     defused: bool,
-    armed_line: u32,
+    armed_location: panic::Location<'static>,
 }
 
 impl DropBomb {
     /// Arm a [`DropBomb`]. If the value is dropped without being [`defused`][Self::defused], then
     /// it will panic. It is expected that the command wrapper uses `#[track_caller]` to help
-    /// propagate the caller info from rmake.rs.
+    /// propagate the caller location.
     #[track_caller]
-    pub(crate) fn arm<S: AsRef<OsStr>>(command: S) -> DropBomb {
+    pub fn arm<S: AsRef<OsStr>>(command: S) -> DropBomb {
         DropBomb {
             command: command.as_ref().into(),
             defused: false,
-            armed_line: panic::Location::caller().line(),
+            armed_location: *panic::Location::caller(),
         }
     }
 
+    pub fn get_created_location(&self) -> panic::Location<'static> {
+        self.armed_location
+    }
+
     /// Defuse the [`DropBomb`]. This will prevent the drop bomb from panicking when dropped.
-    pub(crate) fn defuse(&mut self) {
+    pub fn defuse(&mut self) {
         self.defused = true;
     }
 }
@@ -41,8 +45,8 @@ impl Drop for DropBomb {
     fn drop(&mut self) {
         if !self.defused && !std::thread::panicking() {
             panic!(
-                "command constructed but not executed at line {}: `{}`",
-                self.armed_line,
+                "command constructed at `{}` was dropped without being executed: `{}`",
+                self.armed_location,
                 self.command.to_string_lossy()
             )
         }
diff --git a/src/tools/run-make-support/src/drop_bomb/tests.rs b/src/tools/build_helper/src/drop_bomb/tests.rs
index 4a488c0f670..4a488c0f670 100644
--- a/src/tools/run-make-support/src/drop_bomb/tests.rs
+++ b/src/tools/build_helper/src/drop_bomb/tests.rs
diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs
index 15807d1c0d8..4a4f0ca2a9d 100644
--- a/src/tools/build_helper/src/lib.rs
+++ b/src/tools/build_helper/src/lib.rs
@@ -1,6 +1,7 @@
 //! Types and functions shared across tools in this workspace.
 
 pub mod ci;
+pub mod drop_bomb;
 pub mod git;
 pub mod metrics;
 pub mod stage0_parser;
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
index 91c98b3a256..f016a770059 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
+      run: ./target/debug/lintcheck --format json --warn-all
 
     - 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
+      run: ./target/debug/lintcheck --format json --warn-all
 
     - name: Upload head JSON
       uses: actions/upload-artifact@v4
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 70ef2c79364..55281f3cbec 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5236,6 +5236,7 @@ Released 2018-09-13
 [`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
 [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
 [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
+[`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices
 [`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len
 [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
 [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
@@ -5253,6 +5254,7 @@ Released 2018-09-13
 [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
 [`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts
+[`cfg_not_test`]: https://rust-lang.github.io/rust-clippy/master/index.html#cfg_not_test
 [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
 [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
@@ -5539,6 +5541,7 @@ Released 2018-09-13
 [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
 [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
 [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain
+[`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 [`manual_slice_size_calculation`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation
 [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
@@ -5587,6 +5590,7 @@ Released 2018-09-13
 [`missing_assert_message`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_assert_message
 [`missing_asserts_for_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_asserts_for_indexing
 [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
+[`missing_const_for_thread_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_thread_local
 [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
 [`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
 [`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
@@ -5701,6 +5705,7 @@ Released 2018-09-13
 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
+[`panicking_overflow_checks`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_overflow_checks
 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 [`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields
 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
@@ -5797,6 +5802,7 @@ Released 2018-09-13
 [`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block
 [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
 [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
+[`set_contains_or_insert`]: https://rust-lang.github.io/rust-clippy/master/index.html#set_contains_or_insert
 [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
 [`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index cfd34c7d2a7..ad29339a84a 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -348,6 +348,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
 * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
 * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
 * [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist)
+* [`needless_pass_by_ref_mut`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut)
 * [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option)
 * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer)
 * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
@@ -454,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the
 * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
 * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
 
-**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
 
 ---
 **Affected lints:**
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index 62ed55beb1f..319b72e8c5d 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -1,6 +1,10 @@
 avoid-breaking-exported-api = false
 
 [[disallowed-methods]]
+path = "rustc_lint::context::LintContext::lint"
+reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
+
+[[disallowed-methods]]
 path = "rustc_lint::context::LintContext::span_lint"
 reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
 
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index dbab3b106a8..7f53aad6793 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -31,6 +31,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "OCaml",
     "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry",
     "WebGL", "WebGL2", "WebGPU",
+    "WebP", "OpenExr", "YCbCr", "sRGB",
     "TensorFlow",
     "TrueType",
     "iOS", "macOS", "FreeBSD",
@@ -262,7 +263,7 @@ define_Conf! {
     /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
     /// ```
     (arithmetic_side_effects_allowed_unary: FxHashSet<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.
+    /// 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.
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index a5761d3270c..fc56ac51796 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -25,8 +25,8 @@ msrv_aliases! {
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
     1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
     1,63,0 { CLONE_INTO }
-    1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
-    1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST }
+    1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_FN }
+    1,59,0 { THREAD_LOCAL_CONST_INIT }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
     1,56,0 { CONST_FN_UNION }
     1,55,0 { SEEK_REWIND }
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 2e56eb8ec15..d762e30ef02 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -273,7 +273,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
     result.push_str(&if enable_msrv {
         formatdoc!(
             r#"
-            use clippy_utils::msrvs::{{self, Msrv}};
+            use clippy_config::msrvs::{{self, Msrv}};
             {pass_import}
             use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
             use rustc_session::impl_lint_pass;
@@ -399,7 +399,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
         let _: fmt::Result = writedoc!(
             lint_file_contents,
             r#"
-                use clippy_utils::msrvs::{{self, Msrv}};
+                use clippy_config::msrvs::{{self, Msrv}};
                 use rustc_lint::{{{context_import}, LintContext}};
 
                 use super::{name_upper};
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
index 57a5cd8fba8..96e9c949b75 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
-use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -41,61 +40,80 @@ impl AlmostCompleteRange {
 }
 impl EarlyLintPass for AlmostCompleteRange {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
-        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
-            let ctxt = e.span.ctxt();
-            let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
-                && let Some(end) = walk_span_to_context(end.span, ctxt)
-                && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
-            {
-                Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
-            } else {
-                None
-            };
-            check_range(cx, e.span, start, end, sugg);
+        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind
+            && is_incomplete_range(start, end)
+            && !in_external_macro(cx.sess(), e.span)
+        {
+            span_lint_and_then(
+                cx,
+                ALMOST_COMPLETE_RANGE,
+                e.span,
+                "almost complete ascii range",
+                |diag| {
+                    let ctxt = e.span.ctxt();
+                    if let Some(start) = walk_span_to_context(start.span, ctxt)
+                        && let Some(end) = walk_span_to_context(end.span, ctxt)
+                        && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
+                    {
+                        diag.span_suggestion(
+                            trim_span(cx.sess().source_map(), start.between(end)),
+                            "use an inclusive range",
+                            "..=".to_owned(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                },
+            );
         }
     }
 
     fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) {
         if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
             && matches!(kind.node, RangeEnd::Excluded)
+            && is_incomplete_range(start, end)
+            && !in_external_macro(cx.sess(), p.span)
         {
-            let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
-                "..="
-            } else {
-                "..."
-            };
-            check_range(cx, p.span, start, end, Some((kind.span, sugg)));
+            span_lint_and_then(
+                cx,
+                ALMOST_COMPLETE_RANGE,
+                p.span,
+                "almost complete ascii range",
+                |diag| {
+                    diag.span_suggestion(
+                        kind.span,
+                        "use an inclusive range",
+                        if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
+                            "..=".to_owned()
+                        } else {
+                            "...".to_owned()
+                        },
+                        Applicability::MaybeIncorrect,
+                    );
+                },
+            );
         }
     }
 
     extract_msrv_attr!(EarlyContext);
 }
 
-fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
-    if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
-        && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
-        && matches!(
-            (
-                LitKind::from_token_lit(start_token_lit),
-                LitKind::from_token_lit(end_token_lit),
-            ),
-            (
-                Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
-                Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
-            ) | (
-                Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
-                Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
-            ) | (
-                Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
-                Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
+fn is_incomplete_range(start: &Expr, end: &Expr) -> bool {
+    match (&start.peel_parens().kind, &end.peel_parens().kind) {
+        (&ExprKind::Lit(start_lit), &ExprKind::Lit(end_lit)) => {
+            matches!(
+                (LitKind::from_token_lit(start_lit), LitKind::from_token_lit(end_lit),),
+                (
+                    Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
+                    Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
+                ) | (
+                    Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
+                    Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
+                ) | (
+                    Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
+                    Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
+                )
             )
-        )
-        && !in_external_macro(cx.sess(), span)
-    {
-        span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| {
-            if let Some((span, sugg)) = sugg {
-                diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect);
-            }
-        });
+        },
+        _ => false,
     }
 }
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 2003dd1fb0e..ed4cdce8cb8 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -1,7 +1,8 @@
-use clippy_utils::consts::{constant_with_source, Constant, ConstantSource};
+use clippy_utils::consts::{constant, 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};
-use rustc_hir::{Expr, Item, ItemKind, Node};
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -42,17 +43,16 @@ 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), source)) = constant_with_source(cx, cx.typeck_results(), condition) else {
+        let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
             return;
         };
-        if let ConstantSource::Constant = source
-            && let Node::Item(Item {
-                kind: ItemKind::Const(..),
-                ..
-            }) = cx.tcx.parent_hir_node(e.hir_id)
-        {
-            return;
+
+        match condition.kind {
+            ExprKind::Path(..) | ExprKind::Lit(_) => {},
+            _ if is_inside_always_const_context(cx.tcx, e.hir_id) => return,
+            _ => {},
         }
+
         if val {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 406f38f411e..0de0031ed24 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -1,18 +1,16 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::HirNode;
 use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_trait_method, local_is_initialized, path_to_local};
+use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Instance, Mutability};
 use rustc_session::impl_lint_pass;
-use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
-use rustc_span::{ExpnKind, Span, SyntaxContext};
+use rustc_span::{Span, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -68,165 +66,82 @@ impl AssigningClones {
 impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]);
 
 impl<'tcx> LateLintPass<'tcx> for AssigningClones {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) {
-        // Do not fire the lint in macros
-        let ctxt = assign_expr.span().ctxt();
-        let expn_data = ctxt.outer_expn_data();
-        match expn_data.kind {
-            ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return,
-            ExpnKind::Root => {},
-        }
-
-        let ExprKind::Assign(lhs, rhs, _span) = assign_expr.kind else {
-            return;
-        };
-
-        let Some(call) = extract_call(cx, rhs) else {
-            return;
-        };
-
-        if is_ok_to_suggest(cx, lhs, &call, &self.msrv) {
-            suggest(cx, ctxt, assign_expr, lhs, &call);
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
-
-// Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`.
-fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<CallCandidate<'tcx>> {
-    let fn_def_id = clippy_utils::fn_def_id(cx, expr)?;
-
-    // Fast paths to only check method calls without arguments or function calls with a single argument
-    let (target, kind, resolved_method) = match expr.kind {
-        ExprKind::MethodCall(path, receiver, [], _span) => {
-            let args = cx.typeck_results().node_args(expr.hir_id);
-
-            // If we could not resolve the method, don't apply the lint
-            let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
-                return None;
-            };
-            if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone {
-                (TargetTrait::Clone, CallKind::MethodCall { receiver }, resolved_method)
-            } else if is_trait_method(cx, expr, sym::ToOwned) && path.ident.name.as_str() == "to_owned" {
-                (TargetTrait::ToOwned, CallKind::MethodCall { receiver }, resolved_method)
-            } else {
-                return None;
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if let ExprKind::Assign(lhs, rhs, _) = e.kind
+            && let typeck = cx.typeck_results()
+            && let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind {
+                ExprKind::Call(f, [arg])
+                    if let ExprKind::Path(fn_path) = &f.kind
+                        && let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() =>
+                {
+                    (CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id))
+                },
+                ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => {
+                    (CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id))
+                },
+                _ => return,
             }
-        },
-        ExprKind::Call(function, [arg]) => {
-            let kind = cx.typeck_results().node_type(function.hir_id).kind();
-
-            // If we could not resolve the method, don't apply the lint
-            let Ok(Some(resolved_method)) = (match kind {
-                ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args),
-                _ => Ok(None),
-            }) else {
-                return None;
-            };
-            if cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) {
-                (
-                    TargetTrait::ToOwned,
-                    CallKind::FunctionCall { self_arg: arg },
-                    resolved_method,
-                )
-            } else if let Some(trait_did) = cx.tcx.trait_of_item(fn_def_id)
-                && cx.tcx.is_diagnostic_item(sym::Clone, trait_did)
-            {
-                (
-                    TargetTrait::Clone,
-                    CallKind::FunctionCall { self_arg: arg },
-                    resolved_method,
-                )
-            } else {
-                return None;
+            && let ctxt = e.span.ctxt()
+            // Don't lint in macros.
+            && ctxt.is_root()
+            && let which_trait = match fn_name {
+                sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
+                _ if fn_name.as_str() == "to_owned"
+                    && is_diag_trait_item(cx, fn_id, sym::ToOwned)
+                    && self.msrv.meets(msrvs::CLONE_INTO) =>
+                {
+                    CloneTrait::ToOwned
+                },
+                _ => return,
             }
-        },
-        _ => return None,
-    };
-
-    Some(CallCandidate {
-        span: expr.span,
-        target,
-        kind,
-        method_def_id: resolved_method.def_id(),
-    })
-}
-
-// Return true if we find that the called method has a custom implementation and isn't derived or
-// provided by default by the corresponding trait.
-fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool {
-    // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63.
-    // If the current MSRV is below that, don't suggest the lint.
-    if !msrv.meets(msrvs::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) {
-        return false;
-    }
-
-    // If the left-hand side is a local variable, it might be uninitialized at this point.
-    // In that case we do not want to suggest the lint.
-    if let Some(local) = path_to_local(lhs) {
-        // TODO: This check currently bails if the local variable has no initializer.
-        // That is overly conservative - the lint should fire even if there was no initializer,
-        // but the variable has been initialized before `lhs` was evaluated.
-        if !local_is_initialized(cx, local) {
-            return false;
-        }
-    }
-
-    let Some(impl_block) = cx.tcx.impl_of_method(call.method_def_id) else {
-        return false;
-    };
-
-    // If the method implementation comes from #[derive(Clone)], then don't suggest the lint.
-    // Automatically generated Clone impls do not currently override `clone_from`.
-    // See e.g. https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 for more details.
-    if cx.tcx.is_builtin_derived(impl_block) {
-        return false;
-    }
-
-    // If the call expression is inside an impl block that contains the method invoked by the
-    // call expression, we bail out to avoid suggesting something that could result in endless
-    // recursion.
-    if let Some(local_block_id) = impl_block.as_local()
-        && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner()
-    {
-        let impl_block_owner = block.def_id();
-        if cx
-            .tcx
-            .hir()
-            .parent_id_iter(lhs.hir_id)
-            .any(|parent| parent.owner == impl_block_owner)
+            && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args)
+            // TODO: This check currently bails if the local variable has no initializer.
+            // That is overly conservative - the lint should fire even if there was no initializer,
+            // but the variable has been initialized before `lhs` was evaluated.
+            && path_to_local(lhs).map_or(true, |lhs| local_is_initialized(cx, lhs))
+            && let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id())
+            // Derived forms don't implement `clone_from`/`clone_into`.
+            // See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
+            && !cx.tcx.is_builtin_derived(resolved_impl)
+            // Don't suggest calling a function we're implementing.
+            && resolved_impl.as_local().map_or(true, |block_id| {
+                cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id)
+            })
+            && let resolved_assoc_items = cx.tcx.associated_items(resolved_impl)
+            // Only suggest if `clone_from`/`clone_into` is explicitly implemented
+            && resolved_assoc_items.in_definition_order().any(|assoc|
+                match which_trait {
+                    CloneTrait::Clone => assoc.name == sym::clone_from,
+                    CloneTrait::ToOwned => assoc.name.as_str() == "clone_into",
+                }
+            )
+            && !clone_source_borrows_from_dest(cx, lhs, rhs.span)
         {
-            return false;
+            span_lint_and_then(
+                cx,
+                ASSIGNING_CLONES,
+                e.span,
+                match which_trait {
+                    CloneTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient",
+                    CloneTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient",
+                },
+                |diag| {
+                    let mut app = Applicability::Unspecified;
+                    diag.span_suggestion(
+                        e.span,
+                        match which_trait {
+                            CloneTrait::Clone => "use `clone_from()`",
+                            CloneTrait::ToOwned => "use `clone_into()`",
+                        },
+                        build_sugg(cx, ctxt, lhs, fn_arg, which_trait, call_kind, &mut app),
+                        app,
+                    );
+                },
+            );
         }
     }
 
-    // Find the function for which we want to check that it is implemented.
-    let provided_fn = match call.target {
-        TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| {
-            cx.tcx
-                .provided_trait_methods(clone)
-                .find(|item| item.name == sym::clone_from)
-        }),
-        TargetTrait::ToOwned => cx.tcx.get_diagnostic_item(sym::ToOwned).and_then(|to_owned| {
-            cx.tcx
-                .provided_trait_methods(to_owned)
-                .find(|item| item.name.as_str() == "clone_into")
-        }),
-    };
-    let Some(provided_fn) = provided_fn else {
-        return false;
-    };
-
-    if clone_source_borrows_from_dest(cx, lhs, call.span) {
-        return false;
-    }
-
-    // Now take a look if the impl block defines an implementation for the method that we're interested
-    // in. If not, then we're using a default implementation, which is not interesting, so we will
-    // not suggest the lint.
-    let implemented_fns = cx.tcx.impl_item_implementor_ids(impl_block);
-    implemented_fns.contains_key(&provided_fn.def_id)
+    extract_msrv_attr!(LateContext);
 }
 
 /// Checks if the data being cloned borrows from the place that is being assigned to:
@@ -239,16 +154,6 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
 ///
 /// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows.
 fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool {
-    /// If this basic block only exists to drop a local as part of an assignment, returns its
-    /// successor. Otherwise returns the basic block that was passed in.
-    fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock {
-        if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind {
-            target
-        } else {
-            bb
-        }
-    }
-
     let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else {
         return false;
     };
@@ -267,172 +172,123 @@ fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_spa
     //
     // bb2:
     //  s = s_temp
-    for bb in mir.basic_blocks.iter() {
-        let terminator = bb.terminator();
-
-        // Look for the to_owned/clone call.
-        if terminator.source_info.span != call_span {
-            continue;
+    if let Some(terminator) = mir.basic_blocks.iter()
+            .map(mir::BasicBlockData::terminator)
+            .find(|term| term.source_info.span == call_span)
+        && let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind
+        && let [source] = &**args
+        && let mir::Operand::Move(source) = &source.node
+        && let assign_bb = &mir.basic_blocks[assign_bb]
+        && let assign_bb = match assign_bb.terminator().kind {
+            // Skip the drop of the assignment's destination.
+            mir::TerminatorKind::Drop { target, .. } => &mir.basic_blocks[target],
+            _ => assign_bb,
         }
-
-        if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind
-            && let [source] = &**args
-            && let mir::Operand::Move(source) = &source.node
-            && let assign_bb = skip_drop_block(mir, assign_bb)
-            // Skip any storage statements as they are just noise
-            && let Some(assignment) = mir.basic_blocks[assign_bb].statements
-                .iter()
-                .find(|stmt| {
-                    !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_))
-                })
-            && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind
-            && let Some(borrowers) = borrow_map.get(&borrowed.local)
-            && borrowers.contains(source.local)
-        {
-            return true;
-        }
-
-        return false;
+        // Skip any storage statements as they are just noise
+        && let Some(assignment) = assign_bb.statements
+            .iter()
+            .find(|stmt| {
+                !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_))
+            })
+        && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind
+        && let Some(borrowers) = borrow_map.get(&borrowed.local)
+    {
+        borrowers.contains(source.local)
+    } else {
+        false
     }
-    false
-}
-
-fn suggest<'tcx>(
-    cx: &LateContext<'tcx>,
-    ctxt: SyntaxContext,
-    assign_expr: &Expr<'tcx>,
-    lhs: &Expr<'tcx>,
-    call: &CallCandidate<'tcx>,
-) {
-    span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| {
-        let mut applicability = Applicability::Unspecified;
-
-        diag.span_suggestion(
-            assign_expr.span,
-            call.suggestion_msg(),
-            call.suggested_replacement(cx, ctxt, lhs, &mut applicability),
-            applicability,
-        );
-    });
 }
 
-#[derive(Copy, Clone, Debug)]
-enum CallKind<'tcx> {
-    MethodCall { receiver: &'tcx Expr<'tcx> },
-    FunctionCall { self_arg: &'tcx Expr<'tcx> },
-}
-
-#[derive(Copy, Clone, Debug)]
-enum TargetTrait {
+#[derive(Clone, Copy)]
+enum CloneTrait {
     Clone,
     ToOwned,
 }
 
-#[derive(Debug)]
-struct CallCandidate<'tcx> {
-    span: Span,
-    target: TargetTrait,
-    kind: CallKind<'tcx>,
-    // DefId of the called method from an impl block that implements the target trait
-    method_def_id: DefId,
+#[derive(Copy, Clone)]
+enum CallKind {
+    Ufcs,
+    Method,
 }
 
-impl<'tcx> CallCandidate<'tcx> {
-    #[inline]
-    fn message(&self) -> &'static str {
-        match self.target {
-            TargetTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient",
-            TargetTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient",
-        }
-    }
-
-    #[inline]
-    fn suggestion_msg(&self) -> &'static str {
-        match self.target {
-            TargetTrait::Clone => "use `clone_from()`",
-            TargetTrait::ToOwned => "use `clone_into()`",
-        }
-    }
-
-    fn suggested_replacement(
-        &self,
-        cx: &LateContext<'tcx>,
-        ctxt: SyntaxContext,
-        lhs: &Expr<'tcx>,
-        applicability: &mut Applicability,
-    ) -> String {
-        match self.target {
-            TargetTrait::Clone => {
-                match self.kind {
-                    CallKind::MethodCall { receiver } => {
-                        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, "_", applicability)
-                        } else {
-                            // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
-                            Sugg::hir_with_applicability(cx, lhs, "_", applicability)
-                        }
-                        .maybe_par();
-
-                        // Determine whether we need to reference the argument to clone_from().
-                        let clone_receiver_type = cx.typeck_results().expr_ty(receiver);
-                        let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver);
-                        let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
-                        if clone_receiver_type != clone_receiver_adj_type {
-                            // The receiver may have been a value type, so we need to add an `&` to
-                            // be sure the argument to clone_from will be a reference.
-                            arg_sugg = arg_sugg.addr();
-                        };
-
-                        format!("{receiver_sugg}.clone_from({arg_sugg})")
-                    },
-                    CallKind::FunctionCall { self_arg, .. } => {
-                        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, "_", applicability)
-                        } else {
-                            // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
-                            Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr()
-                        };
-                        // The RHS had to be exactly correct before the call, there is no auto-deref for function calls.
-                        let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
-
-                        format!("Clone::clone_from({self_sugg}, {rhs_sugg})")
-                    },
-                }
-            },
-            TargetTrait::ToOwned => {
-                let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                    // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)`
-                    // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)`
-                    let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", applicability).maybe_par();
-                    let inner_type = cx.typeck_results().expr_ty(ref_expr);
-                    // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it
-                    // deref to a mutable reference.
-                    if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) {
-                        sugg
+fn build_sugg<'tcx>(
+    cx: &LateContext<'tcx>,
+    ctxt: SyntaxContext,
+    lhs: &'tcx Expr<'_>,
+    fn_arg: &'tcx Expr<'_>,
+    which_trait: CloneTrait,
+    call_kind: CallKind,
+    app: &mut Applicability,
+) -> String {
+    match which_trait {
+        CloneTrait::Clone => {
+            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)
                     } else {
-                        sugg.mut_addr()
+                        // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
+                        Sugg::hir_with_applicability(cx, lhs, "_", app)
                     }
+                    .maybe_par();
+
+                    // Determine whether we need to reference the argument to clone_from().
+                    let clone_receiver_type = cx.typeck_results().expr_ty(fn_arg);
+                    let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(fn_arg);
+                    let mut arg_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    if clone_receiver_type != clone_receiver_adj_type {
+                        // The receiver may have been a value type, so we need to add an `&` to
+                        // be sure the argument to clone_from will be a reference.
+                        arg_sugg = arg_sugg.addr();
+                    };
+
+                    format!("{receiver_sugg}.clone_from({arg_sugg})")
+                },
+                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)
+                    } else {
+                        // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
+                        Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr()
+                    };
+                    // The RHS had to be exactly correct before the call, there is no auto-deref for function calls.
+                    let rhs_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+
+                    format!("Clone::clone_from({self_sugg}, {rhs_sugg})")
+                },
+            }
+        },
+        CloneTrait::ToOwned => {
+            let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
+                // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)`
+                // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)`
+                let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_par();
+                let inner_type = cx.typeck_results().expr_ty(ref_expr);
+                // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it
+                // deref to a mutable reference.
+                if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) {
+                    sugg
                 } else {
-                    // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)`
-                    // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)`
-                    Sugg::hir_with_applicability(cx, lhs, "_", applicability)
-                        .maybe_par()
-                        .mut_addr()
-                };
-
-                match self.kind {
-                    CallKind::MethodCall { receiver } => {
-                        let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
-                        format!("{receiver_sugg}.clone_into({rhs_sugg})")
-                    },
-                    CallKind::FunctionCall { self_arg, .. } => {
-                        let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
-                        format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})")
-                    },
+                    sugg.mut_addr()
                 }
-            },
-        }
+            } else {
+                // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)`
+                // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)`
+                Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_par().mut_addr()
+            };
+
+            match call_kind {
+                CallKind::Method => {
+                    let receiver_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    format!("{receiver_sugg}.clone_into({rhs_sugg})")
+                },
+                CallKind::Ufcs => {
+                    let self_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})")
+                },
+            }
+        },
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index f25a474d9bb..d4a1e2780d0 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -11,21 +11,25 @@ use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for calls to await while holding a non-async-aware MutexGuard.
+    /// Checks for calls to `await` while holding a non-async-aware
+    /// `MutexGuard`.
     ///
     /// ### Why is this bad?
-    /// The Mutex types found in std::sync and parking_lot
-    /// are not designed to operate in an async context across await points.
+    /// The Mutex types found in [`std::sync`][https://doc.rust-lang.org/stable/std/sync/] and
+    /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are
+    /// not designed to operate in an async context across await points.
     ///
-    /// There are two potential solutions. One is to use an async-aware Mutex
-    /// type. Many asynchronous foundation crates provide such a Mutex type. The
-    /// other solution is to ensure the mutex is unlocked before calling await,
-    /// either by introducing a scope or an explicit call to Drop::drop.
+    /// There are two potential solutions. One is to use an async-aware `Mutex`
+    /// type. Many asynchronous foundation crates provide such a `Mutex` type.
+    /// The other solution is to ensure the mutex is unlocked before calling
+    /// `await`, either by introducing a scope or an explicit call to
+    /// [`Drop::drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html).
     ///
     /// ### Known problems
     /// Will report false positive for explicitly dropped guards
-    /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
-    /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
+    /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A
+    /// workaround for this is to wrap the `.lock()` call in a block instead of
+    /// explicitly dropping the guard.
     ///
     /// ### Example
     /// ```no_run
@@ -73,11 +77,11 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
+    /// Checks for calls to `await` while holding a `RefCell`, `Ref`, or `RefMut`.
     ///
     /// ### Why is this bad?
     /// `RefCell` refs only check for exclusive mutable access
-    /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
+    /// at runtime. Holding a `RefCell` ref across an await suspension point
     /// risks panics from a mutable ref shared while other refs are outstanding.
     ///
     /// ### Known problems
@@ -131,13 +135,13 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Allows users to configure types which should not be held across `await`
+    /// Allows users to configure types which should not be held across await
     /// suspension points.
     ///
     /// ### Why is this bad?
-    /// There are some types which are perfectly "safe" to be used concurrently
-    /// from a memory access perspective but will cause bugs at runtime if they
-    /// are held in such a way.
+    /// There are some types which are perfectly safe to use concurrently from
+    /// a memory access perspective, but that will cause bugs at runtime if
+    /// they are held in such a way.
     ///
     /// ### Example
     ///
@@ -228,15 +232,15 @@ impl AwaitHolding {
                         cx,
                         AWAIT_HOLDING_LOCK,
                         ty_cause.source_info.span,
-                        "this `MutexGuard` is held across an `await` point",
+                        "this `MutexGuard` is held across an await point",
                         |diag| {
                             diag.help(
                                 "consider using an async-aware `Mutex` type or ensuring the \
-                                `MutexGuard` is dropped before calling await",
+                                `MutexGuard` is dropped before calling `await`",
                             );
                             diag.span_note(
                                 await_points(),
-                                "these are all the `await` points this lock is held through",
+                                "these are all the await points this lock is held through",
                             );
                         },
                     );
@@ -245,12 +249,12 @@ impl AwaitHolding {
                         cx,
                         AWAIT_HOLDING_REFCELL_REF,
                         ty_cause.source_info.span,
-                        "this `RefCell` reference is held across an `await` point",
+                        "this `RefCell` reference is held across an await point",
                         |diag| {
                             diag.help("ensure the reference is dropped before calling `await`");
                             diag.span_note(
                                 await_points(),
-                                "these are all the `await` points this reference is held through",
+                                "these are all the await points this reference is held through",
                             );
                         },
                     );
@@ -268,7 +272,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa
         AWAIT_HOLDING_INVALID_TYPE,
         span,
         format!(
-            "`{}` may not be held across an `await` point per `clippy.toml`",
+            "`{}` may not be held across an await point per `clippy.toml`",
             disallowed.path()
         ),
         |diag| {
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 cfb76cab6dc..561ca9bd986 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,13 +1,11 @@
-use clippy_utils::higher::If;
-use rustc_ast::LitKind;
-use rustc_hir::{Block, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{in_constant, is_else_clause, is_integer_literal};
+use clippy_utils::{in_constant, is_else_clause};
+use rustc_ast::LitKind;
 use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -47,80 +45,64 @@ declare_clippy_lint! {
 declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
 
 impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
-            check_if_else(cx, expr);
-        }
-    }
-}
-
-fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-    if let Some(If {
-        cond,
-        then,
-        r#else: Some(r#else),
-    }) = If::hir(expr)
-        && let Some(then_lit) = int_literal(then)
-        && let Some(else_lit) = int_literal(r#else)
-    {
-        let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
-            false
-        } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) {
-            true
-        } else {
-            // Expression isn't boolean, exit
-            return;
-        };
-        let mut applicability = Applicability::MachineApplicable;
-        let snippet = {
-            let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
-            if inverted {
-                sugg = !sugg;
-            }
-            sugg
-        };
-
-        let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::If(cond, then, Some(else_)) = expr.kind
+            && matches!(cond.kind, ExprKind::DropTemps(_))
+            && let Some(then_lit) = as_int_bool_lit(then)
+            && let Some(else_lit) = as_int_bool_lit(else_)
+            && then_lit != else_lit
+            && !expr.span.from_expansion()
+            && !in_constant(cx, expr.hir_id)
+        {
+            let ty = cx.typeck_results().expr_ty(then);
+            let mut applicability = Applicability::MachineApplicable;
+            let snippet = {
+                let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
+                if !then_lit {
+                    sugg = !sugg;
+                }
+                sugg
+            };
+            let suggestion = {
+                let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
+                // when used in else clause if statement should be wrapped in curly braces
+                if is_else_clause(cx.tcx, expr) {
+                    s = s.blockify();
+                }
+                s
+            };
 
-        let suggestion = {
-            let wrap_in_curly = is_else_clause(cx.tcx, expr);
-            let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
-            if wrap_in_curly {
-                s = s.blockify();
-            }
-            s
-        }; // when used in else clause if statement should be wrapped in curly braces
+            let into_snippet = snippet.clone().maybe_par();
+            let as_snippet = snippet.as_ty(ty);
 
-        let into_snippet = snippet.clone().maybe_par();
-        let as_snippet = snippet.as_ty(ty);
-
-        span_lint_and_then(
-            cx,
-            BOOL_TO_INT_WITH_IF,
-            expr.span,
-            "boolean to int conversion using if",
-            |diag| {
-                diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
-                diag.note(format!(
-                    "`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
-                ));
-            },
-        );
-    };
+            span_lint_and_then(
+                cx,
+                BOOL_TO_INT_WITH_IF,
+                expr.span,
+                "boolean to int conversion using if",
+                |diag| {
+                    diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
+                    diag.note(format!(
+                        "`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
+                    ));
+                },
+            );
+        }
+    }
 }
 
-// If block contains only a int literal expression, return literal expression
-fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
-    if let ExprKind::Block(block, _) = expr.kind
-        && let Block {
-            stmts: [], // Shouldn't lint if statements with side effects
-            expr: Some(expr),
-            ..
-        } = block
-        && let ExprKind::Lit(lit) = &expr.kind
-        && let LitKind::Int(_, _) = lit.node
+fn as_int_bool_lit(e: &Expr<'_>) -> Option<bool> {
+    if let ExprKind::Block(b, _) = e.kind
+        && b.stmts.is_empty()
+        && let Some(e) = b.expr
+        && let ExprKind::Lit(lit) = e.kind
+        && let LitKind::Int(x, _) = lit.node
     {
-        Some(expr)
+        match x.get() {
+            0 => Some(false),
+            1 => Some(true),
+            _ => None,
+        }
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/byte_char_slices.rs b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs
new file mode 100644
index 00000000000..a9fe190f177
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs
@@ -0,0 +1,80 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::{BorrowKind, Expr, ExprKind, Mutability};
+use rustc_ast::token::{Lit, LitKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for hard to read slices of byte characters, that could be more easily expressed as a
+    /// byte string.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Potentially makes the string harder to read.
+    ///
+    /// ### Example
+    /// ```ignore
+    /// &[b'H', b'e', b'l', b'l', b'o'];
+    /// ```
+    /// Use instead:
+    /// ```ignore
+    /// b"Hello"
+    /// ```
+    #[clippy::version = "1.68.0"]
+    pub BYTE_CHAR_SLICES,
+    style,
+    "hard to read byte char slice"
+}
+declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]);
+
+impl EarlyLintPass for ByteCharSlice {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if let Some(slice) = is_byte_char_slices(expr)
+            && !expr.span.from_expansion()
+        {
+            span_lint_and_sugg(
+                cx,
+                BYTE_CHAR_SLICES,
+                expr.span,
+                "can be more succinctly written as a byte str",
+                "try",
+                format!("b\"{slice}\""),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+}
+
+fn is_byte_char_slices(expr: &Expr) -> Option<String> {
+    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind {
+        match &expr.kind {
+            ExprKind::Array(members) => {
+                if members.is_empty() {
+                    return None;
+                }
+
+                members
+                    .iter()
+                    .map(|member| match &member.kind {
+                        ExprKind::Lit(Lit {
+                            kind: LitKind::Byte,
+                            symbol,
+                            ..
+                        }) => Some(symbol.as_str()),
+                        _ => None,
+                    })
+                    .map(|maybe_quote| match maybe_quote {
+                        Some("\"") => Some("\\\""),
+                        Some("\\'") => Some("'"),
+                        other => other,
+                    })
+                    .collect::<Option<String>>()
+            },
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index e60c36ced75..54f0c7c4687 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -32,7 +32,7 @@ use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from any numerical to a float type where
+    /// Checks for casts from any numeric type to a float type where
     /// the receiving type cannot store all values from the original type without
     /// rounding errors. This possible rounding is to be expected, so this lint is
     /// `Allow` by default.
@@ -58,14 +58,14 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from a signed to an unsigned numerical
+    /// Checks for casts from a signed to an unsigned numeric
     /// type. In this case, negative values wrap around to large positive values,
-    /// which can be quite surprising in practice. However, as the cast works as
+    /// which can be quite surprising in practice. However, since the cast works as
     /// defined, this lint is `Allow` by default.
     ///
     /// ### Why is this bad?
     /// Possibly surprising results. You can activate this lint
-    /// as a one-time check to see where numerical wrapping can arise.
+    /// as a one-time check to see where numeric wrapping can arise.
     ///
     /// ### Example
     /// ```no_run
@@ -80,7 +80,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts between numerical types that may
+    /// Checks for casts between numeric types that may
     /// truncate large values. This is expected behavior, so the cast is `Allow` by
     /// default. It suggests user either explicitly ignore the lint,
     /// or use `try_from()` and handle the truncation, default, or panic explicitly.
@@ -120,17 +120,16 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for casts from an unsigned type to a signed type of
-    /// the same size, or possibly smaller due to target dependent integers.
-    /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is
-    /// changed at the bit level, and the binary representation of the value is
+    /// the same size, or possibly smaller due to target-dependent integers.
+    /// Performing such a cast is a no-op for the compiler (that is, nothing is
+    /// changed at the bit level), and the binary representation of the value is
     /// reinterpreted. This can cause wrapping if the value is too big
     /// for the target signed type. However, the cast works as defined, so this lint
     /// is `Allow` by default.
     ///
     /// ### Why is this bad?
     /// While such a cast is not bad in itself, the results can
-    /// be surprising when this is not the intended behavior, as demonstrated by the
-    /// example below.
+    /// be surprising when this is not the intended behavior:
     ///
     /// ### Example
     /// ```no_run
@@ -144,16 +143,16 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts between numerical types that may
-    /// be replaced by safe conversion functions.
+    /// Checks for casts between numeric types that can be replaced by safe
+    /// conversion functions.
     ///
     /// ### Why is this bad?
-    /// Rust's `as` keyword will perform many kinds of
-    /// conversions, including silently lossy conversions. Conversion functions such
-    /// as `i32::from` will only perform lossless conversions. Using the conversion
-    /// functions prevents conversions from turning into silent lossy conversions if
-    /// the types of the input expressions ever change, and make it easier for
-    /// people reading the code to know that the conversion is lossless.
+    /// Rust's `as` keyword will perform many kinds of conversions, including
+    /// silently lossy conversions. Conversion functions such as `i32::from`
+    /// will only perform lossless conversions. Using the conversion functions
+    /// prevents conversions from becoming silently lossy if the input types
+    /// ever change, and makes it clear for people reading the code that the
+    /// conversion is lossless.
     ///
     /// ### Example
     /// ```no_run
@@ -177,19 +176,21 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts to the same type, casts of int literals to integer types, casts of float
-    /// literals to float types and casts between raw pointers without changing type or constness.
+    /// Checks for casts to the same type, casts of int literals to integer
+    /// types, casts of float literals to float types, and casts between raw
+    /// pointers that don't change type or constness.
     ///
     /// ### Why is this bad?
     /// It's just unnecessary.
     ///
     /// ### Known problems
-    /// When the expression on the left is a function call, the lint considers the return type to be
-    /// a type alias if it's aliased through a `use` statement
-    /// (like `use std::io::Result as IoResult`). It will not lint such cases.
+    /// When the expression on the left is a function call, the lint considers
+    /// the return type to be a type alias if it's aliased through a `use`
+    /// statement (like `use std::io::Result as IoResult`). It will not lint
+    /// such cases.
     ///
-    /// This check is also rather primitive. It will only work on primitive types without any
-    /// intermediate references, raw pointers and trait objects may or may not work.
+    /// This check will only work on primitive types without any intermediate
+    /// references: raw pointers and trait objects may or may not work.
     ///
     /// ### Example
     /// ```no_run
@@ -211,17 +212,17 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts, using `as` or `pointer::cast`,
-    /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
+    /// Checks for casts, using `as` or `pointer::cast`, from a
+    /// less strictly aligned pointer to a more strictly aligned pointer.
     ///
     /// ### Why is this bad?
-    /// Dereferencing the resulting pointer may be undefined
-    /// behavior.
+    /// Dereferencing the resulting pointer may be undefined behavior.
     ///
     /// ### Known problems
-    /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
-    /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
-    /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
+    /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or
+    /// similar on the resulting pointer is fine. Is over-zealous: casts with
+    /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be
+    /// fine. Miri is able to do a more in-depth analysis.
     ///
     /// ### Example
     /// ```no_run
@@ -234,20 +235,21 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub CAST_PTR_ALIGNMENT,
     pedantic,
-    "cast from a pointer to a more-strictly-aligned pointer"
+    "cast from a pointer to a more strictly aligned pointer"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts of function pointers to something other than usize
+    /// Checks for casts of function pointers to something other than `usize`.
     ///
     /// ### Why is this bad?
-    /// Casting a function pointer to anything other than usize/isize is not portable across
-    /// architectures, because you end up losing bits if the target type is too small or end up with a
-    /// bunch of extra bits that waste space and add more instructions to the final binary than
-    /// strictly necessary for the problem
+    /// Casting a function pointer to anything other than `usize`/`isize` is
+    /// not portable across architectures. If the target type is too small the
+    /// address would be truncated, and target types larger than `usize` are
+    /// unnecessary.
     ///
-    /// Casting to isize also doesn't make sense since there are no signed addresses.
+    /// Casting to `isize` also doesn't make sense, since addresses are never
+    /// signed.
     ///
     /// ### Example
     /// ```no_run
@@ -263,17 +265,17 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub FN_TO_NUMERIC_CAST,
     style,
-    "casting a function pointer to a numeric type other than usize"
+    "casting a function pointer to a numeric type other than `usize`"
 }
 
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for casts of a function pointer to a numeric type not wide enough to
-    /// store address.
+    /// store an address.
     ///
     /// ### Why is this bad?
     /// Such a cast discards some bits of the function's address. If this is intended, it would be more
-    /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
+    /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with
     /// a comment) to perform the truncation.
     ///
     /// ### Example
@@ -306,7 +308,7 @@ declare_clippy_lint! {
     /// ### Why restrict this?
     /// Casting a function pointer to an integer can have surprising results and can occur
     /// accidentally if parentheses are omitted from a function call. If you aren't doing anything
-    /// low-level with function pointers then you can opt-out of casting functions to integers in
+    /// low-level with function pointers then you can opt out of casting functions to integers in
     /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
     /// pointer casts in your code.
     ///
@@ -349,8 +351,8 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// In general, casting values to smaller types is
     /// error-prone and should be avoided where possible. In the particular case of
-    /// converting a character literal to u8, it is easy to avoid by just using a
-    /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
+    /// converting a character literal to `u8`, it is easy to avoid by just using a
+    /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter
     /// than `'a' as u8`.
     ///
     /// ### Example
@@ -371,12 +373,13 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `as` casts between raw pointers without changing its mutability,
-    /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
+    /// Checks for `as` casts between raw pointers that don't change their
+    /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`.
     ///
     /// ### Why is this bad?
-    /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because
-    /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
+    /// Though `as` casts between raw pointers are not terrible,
+    /// `pointer::cast` is safer because it cannot accidentally change the
+    /// pointer's mutability, nor cast the pointer to other types like `usize`.
     ///
     /// ### Example
     /// ```no_run
@@ -395,12 +398,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.51.0"]
     pub PTR_AS_PTR,
     pedantic,
-    "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
+    "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to
+    /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to
     /// `*mut T` and `*mut T` to `*const T`.
     ///
     /// ### Why is this bad?
@@ -423,12 +426,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.72.0"]
     pub PTR_CAST_CONSTNESS,
     pedantic,
-    "casting using `as` from and to raw pointers to change constness when specialized methods apply"
+    "casting using `as` on raw pointers to change constness when specialized methods apply"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from an enum type to an integral type which will definitely truncate the
+    /// Checks for casts from an enum type to an integral type that will definitely truncate the
     /// value.
     ///
     /// ### Why is this bad?
@@ -442,7 +445,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.61.0"]
     pub CAST_ENUM_TRUNCATION,
     suspicious,
-    "casts from an enum type to an integral type which will truncate the value"
+    "casts from an enum type to an integral type that will truncate the value"
 }
 
 declare_clippy_lint! {
@@ -621,7 +624,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
+    /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer.
     ///
     /// ### Why is this bad?
     /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 2c168405ee2..86c5f6b9f0b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -92,7 +92,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
             cx,
             PTR_AS_PTR,
             expr.span,
-            "`as` casting between raw pointers without changing its mutability",
+            "`as` casting between raw pointers without changing their constness",
             help,
             final_suggestion,
             app,
diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
new file mode 100644
index 00000000000..b54f392bf2f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
@@ -0,0 +1,60 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::NestedMetaItem;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`)
+    ///
+    /// ### Why is this bad?
+    /// This may give the false impression that a codebase has 100% coverage, yet actually has untested code.
+    /// Enabling this also guards against excessive mockery as well, which is an anti-pattern.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # fn important_check() {}
+    /// #[cfg(not(test))]
+    /// important_check(); // I'm not actually tested, but not including me will falsely increase coverage!
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn important_check() {}
+    /// important_check();
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub CFG_NOT_TEST,
+    restriction,
+    "enforce against excluding code from test builds"
+}
+
+declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]);
+
+impl EarlyLintPass for CfgNotTest {
+    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) {
+        if attr.has_name(rustc_span::sym::cfg) && contains_not_test(attr.meta_item_list().as_deref(), false) {
+            span_lint_and_then(
+                cx,
+                CFG_NOT_TEST,
+                attr.span,
+                "code is excluded from test builds",
+                |diag| {
+                    diag.help("consider not excluding any code from test builds");
+                    diag.note_once("this could increase code coverage despite not actually being tested");
+                },
+            );
+        }
+    }
+}
+
+fn contains_not_test(list: Option<&[NestedMetaItem]>, not: bool) -> bool {
+    list.is_some_and(|list| {
+        list.iter().any(|item| {
+            item.ident().is_some_and(|ident| match ident.name {
+                rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not),
+                rustc_span::sym::test => not,
+                _ => contains_not_test(item.meta_item_list(), not),
+            })
+        })
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 638de5e818c..eabc67601a2 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -8,8 +8,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
     #[cfg(feature = "internal")]
-    crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
-    #[cfg(feature = "internal")]
     crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
@@ -73,6 +71,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
     crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
     crate::box_default::BOX_DEFAULT_INFO,
+    crate::byte_char_slices::BYTE_CHAR_SLICES_INFO,
     crate::cargo::CARGO_COMMON_METADATA_INFO,
     crate::cargo::LINT_GROUPS_PRIORITY_INFO,
     crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
@@ -103,6 +102,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::casts::REF_AS_PTR_INFO,
     crate::casts::UNNECESSARY_CAST_INFO,
     crate::casts::ZERO_PTR_INFO,
+    crate::cfg_not_test::CFG_NOT_TEST_INFO,
     crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
     crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
     crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
@@ -313,6 +313,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
     crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
     crate::manual_retain::MANUAL_RETAIN_INFO,
+    crate::manual_rotate::MANUAL_ROTATE_INFO,
     crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO,
     crate::manual_string_new::MANUAL_STRING_NEW_INFO,
     crate::manual_strip::MANUAL_STRIP_INFO,
@@ -503,6 +504,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO,
     crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO,
     crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
+    crate::missing_const_for_thread_local::MISSING_CONST_FOR_THREAD_LOCAL_INFO,
     crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
     crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
     crate::missing_fields_in_debug::MISSING_FIELDS_IN_DEBUG_INFO,
@@ -585,12 +587,12 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::operators::VERBOSE_BIT_MASK_INFO,
     crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
     crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO,
-    crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO,
     crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO,
     crate::panic_unimplemented::PANIC_INFO,
     crate::panic_unimplemented::TODO_INFO,
     crate::panic_unimplemented::UNIMPLEMENTED_INFO,
     crate::panic_unimplemented::UNREACHABLE_INFO,
+    crate::panicking_overflow_checks::PANICKING_OVERFLOW_CHECKS_INFO,
     crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO,
     crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO,
     crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
@@ -644,6 +646,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO,
     crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
     crate::serde_api::SERDE_API_MISUSE_INFO,
+    crate::set_contains_or_insert::SET_CONTAINS_OR_INSERT_INFO,
     crate::shadow::SHADOW_REUSE_INFO,
     crate::shadow::SHADOW_SAME_INFO,
     crate::shadow::SHADOW_UNRELATED_INFO,
@@ -679,7 +682,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO,
     crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO,
     crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO,
-    crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO,
     crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
     crate::to_string_trait_impl::TO_STRING_TRAIT_IMPL_INFO,
     crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 2b3f4854255..72fa05be3cc 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro};
+use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             // Avoid cases already linted by `field_reassign_with_default`
             && !self.reassigned_linted.contains(&expr.span)
             && let ExprKind::Call(path, ..) = expr.kind
-            && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+            && !in_automatically_derived(cx.tcx, expr.hir_id)
             && let ExprKind::Path(ref qpath) = path.kind
             && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
@@ -113,9 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for Default {
         // start from the `let mut _ = _::default();` and look at all the following
         // statements, see if they re-assign the fields of the binding
         let stmts_head = match block.stmts {
+            [] | [_] => return,
             // Skip the last statement since there cannot possibly be any following statements that re-assign fields.
-            [head @ .., _] if !head.is_empty() => head,
-            _ => return,
+            [head @ .., _] => head,
         };
         for (stmt_idx, stmt) in stmts_head.iter().enumerate() {
             // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
@@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind
                 // only take `let ...` statements
                 && let Some(expr) = local.init
-                && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+                && !in_automatically_derived(cx.tcx, expr.hir_id)
                 && !expr.span.from_expansion()
                 // only take bindings to identifiers
                 && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind
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 ff631909bcb..9af73db6849 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -50,6 +50,8 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
 impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
         let hir = cx.tcx.hir();
+        // NOTE: this is different from `clippy_utils::is_inside_always_const_context`.
+        // Inline const supports type inference.
         let is_parent_const = matches!(
             hir.body_const_context(hir.body_owner_def_id(body.id())),
             Some(ConstContext::Const { inline: false } | ConstContext::Static(_))
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index a115f8d0631..253f9959e13 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,7 +3,8 @@ 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::{
-    expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
+    expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy,
+    ExprUseNode,
 };
 use core::mem;
 use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
@@ -175,6 +176,7 @@ struct StateData<'tcx> {
     adjusted_ty: Ty<'tcx>,
 }
 
+#[derive(Debug)]
 struct DerefedBorrow {
     count: usize,
     msg: &'static str,
@@ -182,6 +184,7 @@ struct DerefedBorrow {
     for_field_access: Option<Symbol>,
 }
 
+#[derive(Debug)]
 enum State {
     // Any number of deref method calls.
     DerefMethod {
@@ -744,7 +747,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo
     }
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 enum TyCoercionStability {
     Deref,
     Reborrow,
@@ -1042,16 +1045,28 @@ fn report<'tcx>(
                 return;
             }
 
-            let (prefix, precedence) = if let Some(mutability) = mutability
-                && !typeck.expr_ty(expr).is_ref()
+            let ty = typeck.expr_ty(expr);
+
+            // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst).
+            if let ty::Ref(_, dst, _) = data.adjusted_ty.kind()
+                && dst.is_slice()
             {
-                let prefix = match mutability {
-                    Mutability::Not => "&",
-                    Mutability::Mut => "&mut ",
-                };
-                (prefix, PREC_PREFIX)
-            } else {
-                ("", 0)
+                let (src, n_src_refs) = peel_middle_ty_refs(ty);
+                if n_src_refs >= 2 && src.is_array() {
+                    return;
+                }
+            }
+
+            let (prefix, precedence) = match mutability {
+                Some(mutability) if !ty.is_ref() => {
+                    let prefix = match mutability {
+                        Mutability::Not => "&",
+                        Mutability::Mut => "&mut ",
+                    };
+                    (prefix, PREC_PREFIX)
+                },
+                None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0),
+                _ => ("", 0),
             };
             span_lint_hir_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 9de879604e2..38fe687f7cc 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -1,6 +1,6 @@
 use clippy_config::types::DisallowedPath;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -83,26 +83,26 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr)
-            && let ExprKind::Call(receiver, _) = parent.kind
-            && receiver.hir_id == expr.hir_id
-        {
-            None
-        } else {
-            path_def_id(cx, expr)
+        let (id, span) = match &expr.kind {
+            ExprKind::Path(path)
+                if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) =
+                    cx.qpath_res(path, expr.hir_id) =>
+            {
+                (id, expr.span)
+            },
+            ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => {
+                (id, name.ident.span)
+            },
+            _ => return,
         };
-        let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else {
-            return;
-        };
-        let conf = match self.disallowed.get(&def_id) {
-            Some(&index) => &self.conf_disallowed[index],
-            None => return,
-        };
-        let msg = format!("use of a disallowed method `{}`", conf.path());
-        span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| {
-            if let Some(reason) = conf.reason() {
-                diag.note(reason);
-            }
-        });
+        if let Some(&index) = self.disallowed.get(&id) {
+            let conf = &self.conf_disallowed[index];
+            let msg = format!("use of a disallowed method `{}`", conf.path());
+            span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| {
+                if let Some(reason) = conf.reason() {
+                    diag.note(reason);
+                }
+            });
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 2afbf184117..58809604c37 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_test_module_or_function;
+use clippy_utils::is_in_test;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{Item, Pat, PatKind};
+use rustc_hir::{Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 
@@ -27,52 +27,30 @@ declare_clippy_lint! {
 #[derive(Clone, Debug)]
 pub struct DisallowedNames {
     disallow: FxHashSet<String>,
-    test_modules_deep: u32,
 }
 
 impl DisallowedNames {
     pub fn new(disallowed_names: &[String]) -> Self {
         Self {
             disallow: disallowed_names.iter().cloned().collect(),
-            test_modules_deep: 0,
         }
     }
-
-    fn in_test_module(&self) -> bool {
-        self.test_modules_deep != 0
-    }
 }
 
 impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
-    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
-        }
-    }
-
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        // Check whether we are under the `test` attribute.
-        if self.in_test_module() {
-            return;
-        }
-
-        if let PatKind::Binding(.., ident, _) = pat.kind {
-            if self.disallow.contains(&ident.name.to_string()) {
-                span_lint(
-                    cx,
-                    DISALLOWED_NAMES,
-                    ident.span,
-                    format!("use of a disallowed/placeholder name `{}`", ident.name),
-                );
-            }
-        }
-    }
-
-    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
+        if let PatKind::Binding(.., ident, _) = pat.kind
+            && self.disallow.contains(&ident.name.to_string())
+            && !is_in_test(cx.tcx, pat.hir_id)
+        {
+            span_lint(
+                cx,
+                DISALLOWED_NAMES,
+                ident.span,
+                format!("use of a disallowed/placeholder name `{}`", ident.name),
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index a995f06fb73..5ce11900adf 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -82,30 +82,25 @@ impl EarlyLintPass for DisallowedScriptIdents {
             // Note: `symbol.as_str()` is an expensive operation, thus should not be called
             // more than once for a single symbol.
             let symbol_str = symbol.as_str();
-            if symbol_str.is_ascii() {
-                continue;
-            }
 
-            for c in symbol_str.chars() {
-                // We want to iterate through all the scripts associated with this character
-                // and check whether at least of one scripts is in the whitelist.
-                let forbidden_script = c
-                    .script_extension()
-                    .iter()
-                    .find(|script| !self.whitelist.contains(script));
-                if let Some(script) = forbidden_script {
-                    span_lint(
-                        cx,
-                        DISALLOWED_SCRIPT_IDENTS,
-                        span,
-                        format!(
-                            "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
-                            script.full_name()
-                        ),
-                    );
-                    // We don't want to spawn warning multiple times over a single identifier.
-                    break;
-                }
+            // Check if any character in the symbol is not part of any allowed script.
+            // Fast path for ascii-only idents.
+            if !symbol_str.is_ascii()
+                && let Some(script) = symbol_str.chars().find_map(|c| {
+                    c.script_extension()
+                        .iter()
+                        .find(|script| !self.whitelist.contains(script))
+                })
+            {
+                span_lint(
+                    cx,
+                    DISALLOWED_SCRIPT_IDENTS,
+                    span,
+                    format!(
+                        "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
+                        script.full_name()
+                    ),
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
index 38bc58a5501..bd1cc46e185 100644
--- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
@@ -22,6 +22,7 @@ pub(super) fn check(
     range: Range<usize>,
     mut span: Span,
     containers: &[super::Container],
+    line_break_span: Span,
 ) {
     if doc[range.clone()].contains('\t') {
         // We don't do tab stops correctly.
@@ -46,11 +47,35 @@ pub(super) fn check(
         .sum();
     if ccount < blockquote_level || lcount < list_indentation {
         let msg = if ccount < blockquote_level {
-            "doc quote missing `>` marker"
+            "doc quote line without `>` marker"
         } else {
-            "doc list item missing indentation"
+            "doc list item without indentation"
         };
         span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
+            let snippet = clippy_utils::source::snippet(cx, line_break_span, "");
+            if snippet.chars().filter(|&c| c == '\n').count() > 1
+                && let Some(doc_comment_start) = snippet.rfind('\n')
+                && let doc_comment = snippet[doc_comment_start..].trim()
+                && (doc_comment == "///" || doc_comment == "//!")
+            {
+                // suggest filling in a blank line
+                diag.span_suggestion_with_style(
+                    line_break_span.shrink_to_lo(),
+                    "if this should be its own paragraph, add a blank doc comment line",
+                    format!("\n{doc_comment}"),
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways,
+                );
+                if ccount > 0 || blockquote_level > 0 {
+                    diag.help("if this not intended to be a quote at all, escape it with `\\>`");
+                } else {
+                    let indent = list_indentation - lcount;
+                    diag.help(format!(
+                        "if this is intended to be part of the list, indent {indent} spaces"
+                    ));
+                }
+                return;
+            }
             if ccount == 0 && blockquote_level == 0 {
                 // simpler suggestion style for indentation
                 let indent = list_indentation - lcount;
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 3e210fd153b..a2a1a51920f 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -6,7 +6,8 @@ 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 pulldown_cmark::Event::{
-    Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text,
+    Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start,
+    TaskListMarker, Text,
 };
 use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph};
 use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd};
@@ -747,7 +748,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
             },
             Start(FootnoteDefinition(..)) => in_footnote_definition = true,
             End(TagEnd::FootnoteDefinition) => in_footnote_definition = false,
-            Start(_) | End(_) => (), // We don't care about other tags
+            Start(_) | End(_)  // We don't care about other tags
+            | TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             SoftBreak | HardBreak => {
                 if !containers.is_empty()
                     && let Some((next_event, next_range)) = events.peek()
@@ -762,13 +764,24 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                         range.end..next_range.start,
                         Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
                         &containers[..],
+                        span,
                     );
                 }
             },
-            TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             FootnoteReference(text) | Text(text) => {
                 paragraph_range.end = range.end;
-                ticks_unbalanced |= text.contains('`') && !in_code;
+                let range_ = range.clone();
+                ticks_unbalanced |= text.contains('`')
+                    && !in_code
+                    && doc[range.clone()].bytes().enumerate().any(|(i, c)| {
+                        // scan the markdown source code bytes for backquotes that aren't preceded by backslashes
+                        // - use bytes, instead of chars, to avoid utf8 decoding overhead (special chars are ascii)
+                        // - relevant backquotes are within doc[range], but backslashes are not, because they're not
+                        //   actually part of the rendered text (pulldown-cmark doesn't emit any events for escapes)
+                        // - if `range_.start + i == 0`, then `range_.start + i - 1 == -1`, and since we're working in
+                        //   usize, that would underflow and maybe panic
+                        c == b'`' && (range_.start + i == 0 || doc.as_bytes().get(range_.start + i - 1) != Some(&b'\\'))
+                    });
                 if Some(&text) == in_link.as_ref() || ticks_unbalanced {
                     // Probably a link of the form `<http://example.com>`
                     // Which are represented as a link to "http://example.com" with
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index bb766e96338..99328e3e643 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -33,7 +33,7 @@ declare_clippy_lint! {
     /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`.
     ///
     /// ### Why restrict this?
-    /// To ensure use of big endian or the target’s endianness rather than little endian.
+    /// To ensure use of big-endian or the target’s endianness rather than little-endian.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -51,7 +51,7 @@ declare_clippy_lint! {
     /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`.
     ///
     /// ### Why restrict this?
-    /// To ensure use of little endian or the target’s endianness rather than big endian.
+    /// To ensure use of little-endian or the target’s endianness rather than big-endian.
     ///
     /// ### Example
     /// ```rust,ignore
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index 6fb38a0d6dd..cf85c74e688 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_in_test_function;
+use clippy_utils::is_in_test;
 
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
@@ -41,7 +41,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_
 pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
     if let FnKind::ItemFn(_, generics, _) = kind
         && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
-        && !is_in_test_function(cx.tcx, hir_id)
+        && !is_in_test(cx.tcx, hir_id)
     {
         for param in generics.params {
             if param.is_impl_trait() {
@@ -59,7 +59,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
         && of_trait.is_none()
         && let body = cx.tcx.hir().body(body_id)
         && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
-        && !is_in_test_function(cx.tcx, impl_item.hir_id())
+        && !is_in_test(cx.tcx, impl_item.hir_id())
     {
         for param in impl_item.generics.params {
             if param.is_impl_trait() {
@@ -75,7 +75,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>,
         && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id())
         // ^^ (Will always be a trait)
         && !item.vis_span.is_empty() // Is public
-        && !is_in_test_function(cx.tcx, trait_item.hir_id())
+        && !is_in_test(cx.tcx, trait_item.hir_id())
     {
         for param in trait_item.generics.params {
             if param.is_impl_trait() {
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
index 35b4481bfee..5c63d48adaf 100644
--- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::Msrv;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_in_test_function;
+use clippy_utils::is_in_test;
 use rustc_attr::{StabilityLevel, StableSince};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{Expr, ExprKind, HirId};
@@ -88,7 +88,7 @@ impl IncompatibleMsrv {
             return;
         }
         let version = self.get_def_id_version(cx.tcx, def_id);
-        if self.msrv.meets(version) || is_in_test_function(cx.tcx, node) {
+        if self.msrv.meets(version) || is_in_test(cx.tcx, node) {
             return;
         }
         if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind {
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 9aedf5ec7e8..ec6174bc030 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -91,10 +91,6 @@ declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_S
 
 impl<'tcx> LateLintPass<'tcx> for InherentToString {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
-        if impl_item.span.from_expansion() {
-            return;
-        }
-
         // Check if item is a method called `to_string` and has a parameter 'self'
         if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
             // #11201
@@ -106,6 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             && decl.implicit_self.has_implicit_self()
             && decl.inputs.len() == 1
             && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+            && !impl_item.span.from_expansion()
             // Check if return type is String
             && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
index 1c8fd0a27f9..7f183bb601e 100644
--- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
@@ -1,13 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
+use rustc_span::SyntaxContext;
 use std::borrow::Cow;
-use std::cmp::Reverse;
-use std::collections::BinaryHeap;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -44,38 +43,56 @@ declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]);
 
 impl<'tcx> LateLintPass<'tcx> for NumberedFields {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Struct(path, fields, None) = e.kind {
-            if !fields.is_empty()
-                && !e.span.from_expansion()
-                && fields
-                    .iter()
-                    .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
-                && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
-            {
-                let expr_spans = fields
-                    .iter()
-                    .map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span))
-                    .collect::<BinaryHeap<_>>();
-                let mut appl = Applicability::MachineApplicable;
-                let snippet = format!(
-                    "{}({})",
-                    snippet_with_applicability(cx, path.span(), "..", &mut appl),
-                    expr_spans
-                        .into_iter_sorted()
-                        .map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0)
-                        .intersperse(Cow::Borrowed(", "))
-                        .collect::<String>()
-                );
-                span_lint_and_sugg(
-                    cx,
-                    INIT_NUMBERED_FIELDS,
-                    e.span,
-                    "used a field initializer for a tuple struct",
-                    "try",
-                    snippet,
-                    appl,
-                );
-            }
+        if let ExprKind::Struct(path, fields @ [field, ..], None) = e.kind
+            // If the first character of any field is a digit it has to be a tuple.
+            && field.ident.as_str().as_bytes().first().is_some_and(u8::is_ascii_digit)
+            // Type aliases can't be used as functions.
+            && !matches!(
+                cx.qpath_res(path, e.hir_id),
+                Res::Def(DefKind::TyAlias | DefKind::AssocTy, _)
+            )
+            // This is the only syntax macros can use that works for all struct types.
+            && !e.span.from_expansion()
+            && let mut has_side_effects = false
+            && let Ok(mut expr_spans) = fields
+                .iter()
+                .map(|f| {
+                    has_side_effects |= f.expr.can_have_side_effects();
+                    f.ident.as_str().parse::<usize>().map(|x| (x, f.expr.span))
+                })
+                .collect::<Result<Vec<_>, _>>()
+            // We can only reorder the expressions if there are no side effects.
+            && (!has_side_effects || expr_spans.is_sorted_by_key(|&(idx, _)| idx))
+        {
+            span_lint_and_then(
+                cx,
+                INIT_NUMBERED_FIELDS,
+                e.span,
+                "used a field initializer for a tuple struct",
+                |diag| {
+                    if !has_side_effects {
+                        // We already checked the order if there are side effects.
+                        expr_spans.sort_by_key(|&(idx, _)| idx);
+                    }
+                    let mut app = Applicability::MachineApplicable;
+                    diag.span_suggestion(
+                        e.span,
+                        "use tuple initialization",
+                        format!(
+                            "{}({})",
+                            snippet_with_applicability(cx, path.span(), "..", &mut app),
+                            expr_spans
+                                .into_iter()
+                                .map(
+                                    |(_, span)| snippet_with_context(cx, span, SyntaxContext::root(), "..", &mut app).0
+                                )
+                                .intersperse(Cow::Borrowed(", "))
+                                .collect::<String>()
+                        ),
+                        app,
+                    );
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 860258fd030..5657c58bb0a 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -2,12 +2,11 @@
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::DiagExt;
-use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
 use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{sym, Symbol};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -34,27 +33,23 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
 
 impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind {
-            let attrs = cx.tcx.hir().attrs(item.hir_id());
-            check_attrs(cx, item.ident.name, attrs);
+        if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind
+            && let Some(attr) = cx
+                .tcx
+                .hir()
+                .attrs(item.hir_id())
+                .iter()
+                .find(|a| a.has_name(sym::inline))
+        {
+            span_lint_and_then(
+                cx,
+                INLINE_FN_WITHOUT_BODY,
+                attr.span,
+                format!("use of `#[inline]` on trait method `{}` which has no body", item.ident),
+                |diag| {
+                    diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
+                },
+            );
         }
     }
 }
-
-fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
-    for attr in attrs {
-        if !attr.has_name(sym::inline) {
-            continue;
-        }
-
-        span_lint_and_then(
-            cx,
-            INLINE_FN_WITHOUT_BODY,
-            attr.span,
-            format!("use of `#[inline]` on trait method `{name}` which has no body"),
-            |diag| {
-                diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
-            },
-        );
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 10b00f632bb..5fe152d1e30 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -85,16 +85,19 @@ impl LateLintPass<'_> for InstantSubtraction {
             lhs,
             rhs,
         ) = expr.kind
+            && let typeck = cx.typeck_results()
+            && ty::is_type_diagnostic_item(cx, typeck.expr_ty(lhs), sym::Instant)
         {
+            let rhs_ty = typeck.expr_ty(rhs);
+
             if is_instant_now_call(cx, lhs)
-                && is_an_instant(cx, rhs)
+                && ty::is_type_diagnostic_item(cx, rhs_ty, sym::Instant)
                 && let Some(sugg) = Sugg::hir_opt(cx, rhs)
             {
                 print_manual_instant_elapsed_sugg(cx, expr, sugg);
-            } else if !expr.span.from_expansion()
+            } else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration)
+                && !expr.span.from_expansion()
                 && self.msrv.meets(msrvs::TRY_FROM)
-                && is_an_instant(cx, lhs)
-                && is_a_duration(cx, rhs)
             {
                 print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
             }
@@ -115,16 +118,6 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
     }
 }
 
-fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let expr_ty = cx.typeck_results().expr_ty(expr);
-    ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant)
-}
-
-fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let expr_ty = cx.typeck_results().expr_ty(expr);
-    ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration)
-}
-
 fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index 39223c20470..a88d8e24fda 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -54,36 +54,35 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
 
 impl LateLintPass<'_> for ItemsAfterStatements {
     fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) {
-        if in_external_macro(cx.sess(), block.span) {
-            return;
-        }
-
-        // skip initial items
-        let stmts = block
-            .stmts
-            .iter()
-            .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)));
-
-        // lint on all further items
-        for stmt in stmts {
-            if let StmtKind::Item(item_id) = stmt.kind {
-                let item = cx.tcx.hir().item(item_id);
-                if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) {
-                    return;
-                }
-                if let ItemKind::Macro(..) = item.kind {
-                    // do not lint `macro_rules`, but continue processing further statements
-                    continue;
-                }
-                span_lint_hir(
-                    cx,
-                    ITEMS_AFTER_STATEMENTS,
-                    item.hir_id(),
-                    item.span,
-                    "adding items after statements is confusing, since items exist from the \
-                     start of the scope",
-                );
-            }
+        if block.stmts.len() > 1 {
+            let ctxt = block.span.ctxt();
+            let mut in_external = None;
+            block
+                .stmts
+                .iter()
+                .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)))
+                .filter_map(|stmt| match stmt.kind {
+                    StmtKind::Item(id) => Some(cx.tcx.hir().item(id)),
+                    _ => None,
+                })
+                // Ignore macros since they can only see previously defined locals.
+                .filter(|item| !matches!(item.kind, ItemKind::Macro(..)))
+                // Stop linting if macros define items.
+                .take_while(|item| item.span.ctxt() == ctxt)
+                // Don't use `next` due to the complex filter chain.
+                .for_each(|item| {
+                    // Only do the macro check once, but delay it until it's needed.
+                    if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) {
+                        span_lint_hir(
+                            cx,
+                            ITEMS_AFTER_STATEMENTS,
+                            item.hir_id(),
+                            item.span,
+                            "adding items after statements is confusing, since items exist from the \
+                                start of the scope",
+                        );
+                    }
+                });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 1b5f1b49947..ba0cd5d6eb3 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
+use rustc_span::{sym, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -43,30 +43,27 @@ declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
 
 impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        let name = item.ident.name.as_str();
-        if matches!(name, "iter" | "iter_mut") {
-            if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.owner_id.def_id);
-            }
+        if let TraitItemKind::Fn(fn_sig, _) = &item.kind
+            && matches!(item.ident.name, sym::iter | sym::iter_mut)
+        {
+            check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id);
         }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
-        let name = item.ident.name.as_str();
-        if matches!(name, "iter" | "iter_mut")
+        if let ImplItemKind::Fn(fn_sig, _) = &item.kind
+            && matches!(item.ident.name, sym::iter | sym::iter_mut)
             && !matches!(
                 cx.tcx.parent_hir_node(item.hir_id()),
                 Node::Item(Item { kind: ItemKind::Impl(i), .. }) if i.of_trait.is_some()
             )
         {
-            if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.owner_id.def_id);
-            }
+            check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id);
         }
     }
 }
 
-fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
+fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDefId) {
     if sig.decl.implicit_self.has_implicit_self() {
         let ret_ty = cx
             .tcx
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 6b03f2597b0..1e6404190d3 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -125,13 +125,13 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
 
 impl LateLintPass<'_> for IterWithoutIntoIter {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
-        if !in_external_macro(cx.sess(), item.span)
-            && let ItemKind::Impl(imp) = item.kind
+        if let ItemKind::Impl(imp) = item.kind
             && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
             && let Some(trait_ref) = imp.of_trait
             && trait_ref
                 .trait_def_id()
                 .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
+            && !in_external_macro(cx.sess(), item.span)
             && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
             && let expected_method_name = match mtbl {
                 Mutability::Mut => sym::iter_mut,
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 7f8197c0cc0..b18ab625e60 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -46,12 +46,12 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if !item.span.from_expansion()
-            && let ItemKind::Const(_, generics, _) = &item.kind
+        if let ItemKind::Const(_, generics, _) = &item.kind
             // Since static items may not have generics, skip generic const items.
             // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
             // doesn't account for empty where-clauses that only consist of keyword `where` IINM.
             && generics.params.is_empty() && !generics.has_where_clause_predicates
+            && !item.span.from_expansion()
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
             && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index 0bf7389ef9c..85daadcc537 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -77,17 +77,12 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
-        if in_external_macro(cx.tcx.sess, item.span) {
-            return;
-        }
-        if let ItemKind::Enum(ref def, _) = item.kind {
-            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let ty::Adt(adt, subst) = ty.kind() else {
-                panic!("already checked whether this is an enum")
-            };
-            if adt.variants().len() <= 1 {
-                return;
-            }
+        if let ItemKind::Enum(ref def, _) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && let ty::Adt(adt, subst) = ty.kind()
+            && adt.variants().len() > 1
+            && !in_external_macro(cx.tcx.sess, item.span)
+        {
             let variants_size = AdtVariantInfo::new(cx, *adt, subst);
 
             let mut difference = variants_size[0].size - variants_size[1].size;
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 07488a512a3..602227e4249 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -54,29 +54,26 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeFuture {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if matches!(expr.span.ctxt().outer_expn_data().kind, rustc_span::ExpnKind::Macro(..)) {
-            return;
-        }
-        if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind {
-            if let ExprKind::Call(func, [expr, ..]) = expr.kind
-                && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
-                && let ty = cx.typeck_results().expr_ty(expr)
-                && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
-                && implements_trait(cx, ty, future_trait_def_id, &[])
-                && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
-                && let size = layout.layout.size()
-                && size >= Size::from_bytes(self.future_size_threshold)
-            {
-                span_lint_and_sugg(
-                    cx,
-                    LARGE_FUTURES,
-                    expr.span,
-                    format!("large future with a size of {} bytes", size.bytes()),
-                    "consider `Box::pin` on it",
-                    format!("Box::pin({})", snippet(cx, expr.span, "..")),
-                    Applicability::Unspecified,
-                );
-            }
+        if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind
+            && let ExprKind::Call(func, [arg, ..]) = scrutinee.kind
+            && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
+            && !expr.span.from_expansion()
+            && let ty = cx.typeck_results().expr_ty(arg)
+            && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
+            && implements_trait(cx, ty, future_trait_def_id, &[])
+            && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
+            && let size = layout.layout.size()
+            && size >= Size::from_bytes(self.future_size_threshold)
+        {
+            span_lint_and_sugg(
+                cx,
+                LARGE_FUTURES,
+                arg.span,
+                format!("large future with a size of {} bytes", size.bytes()),
+                "consider `Box::pin` on it",
+                format!("Box::pin({})", snippet(cx, arg.span, "..")),
+                Applicability::Unspecified,
+            );
         }
     }
 }
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 07efee159aa..2688283a6ce 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,4 @@
 use clippy_utils::diagnostics::span_lint_and_note;
-use clippy_utils::is_lint_allowed;
 use clippy_utils::macros::root_macro_call_first_node;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
@@ -52,24 +51,19 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
 
 impl LateLintPass<'_> for LargeIncludeFile {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if let Some(macro_call) = root_macro_call_first_node(cx, expr)
-            && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id)
-            && (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))
-            && let ExprKind::Lit(lit) = &expr.kind
-        {
-            let len = match &lit.node {
+        if let ExprKind::Lit(lit) = &expr.kind
+            && let len = match &lit.node {
                 // include_bytes
                 LitKind::ByteStr(bstr, _) => bstr.len(),
                 // include_str
                 LitKind::Str(sym, _) => sym.as_str().len(),
                 _ => return,
-            };
-
-            if len as u64 <= self.max_file_size {
-                return;
             }
-
+            && len as u64 > self.max_file_size
+            && let Some(macro_call) = root_macro_call_first_node(cx, expr)
+            && (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(
                 cx,
                 LARGE_INCLUDE_FILE,
diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
index eadfeb6e341..a08b40bef37 100644
--- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
@@ -48,15 +48,11 @@ impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]);
 
 impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        let Self { msrv } = self;
-
-        if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) {
-            return;
-        }
-
         // Integer modules are "TBD" deprecated, and the contents are too,
         // so lint on the `use` statement directly.
         if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
+            && self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
+            && !in_external_macro(cx.sess(), item.span)
             && let Some(def_id) = path.res[0].opt_def_id()
         {
             let module = if is_integer_module(cx, def_id) {
@@ -103,12 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        let Self { msrv } = self;
-
-        if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-        let ExprKind::Path(qpath) = expr.kind else {
+        let ExprKind::Path(qpath) = &expr.kind else {
             return;
         };
 
@@ -129,10 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
             )
         // `<integer>::xxx_value` check
         } else if let QPath::TypeRelative(_, last_segment) = qpath
-            && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id()
-            && is_integer_method(cx, def_id)
+            && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id()
             && let Some(par_expr) = get_parent_expr(cx, expr)
-            && let ExprKind::Call(_, _) = par_expr.kind
+            && let ExprKind::Call(_, []) = par_expr.kind
+            && is_integer_method(cx, def_id)
         {
             let name = last_segment.ident.name.as_str();
 
@@ -145,19 +136,20 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
             return;
         };
 
-        if is_from_proc_macro(cx, expr) {
-            return;
+        if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
+            && !in_external_macro(cx.sess(), expr.span)
+            && !is_from_proc_macro(cx, expr)
+        {
+            span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
+                diag.span_suggestion_with_style(
+                    span,
+                    "use the associated constant instead",
+                    sugg,
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways,
+                );
+            });
         }
-
-        span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
-            diag.span_suggestion_with_style(
-                span,
-                "use the associated constant instead",
-                sugg,
-                Applicability::MaybeIncorrect,
-                SuggestionStyle::ShowAlways,
-            );
-        });
     }
 
     extract_msrv_attr!(LateContext);
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 57e0a7aa2c7..4c737371bd2 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -121,11 +121,9 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP
 
 impl<'tcx> LateLintPass<'tcx> for LenZero {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if item.span.from_expansion() {
-            return;
-        }
-
-        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind {
+        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind
+            && !item.span.from_expansion()
+        {
             check_trait_items(cx, item, trait_items);
         }
     }
@@ -162,17 +160,14 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if expr.span.from_expansion() {
-            return;
-        }
-
         if let ExprKind::Let(lt) = expr.kind
-            && has_is_empty(cx, lt.init)
             && match lt.pat.kind {
                 PatKind::Slice([], None, []) => true,
                 PatKind::Lit(lit) if is_empty_string(lit) => true,
                 _ => false,
             }
+            && !expr.span.from_expansion()
+            && has_is_empty(cx, lt.init)
         {
             let mut applicability = Applicability::MachineApplicable;
 
@@ -190,7 +185,9 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             );
         }
 
-        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
+        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind
+            && !expr.span.from_expansion()
+        {
             // expr.span might contains parenthesis, see issue #10529
             let actual_span = span_without_enclosing_paren(cx, expr.span);
             match cmp {
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index a65cb3f4dfb..0e488cee6b7 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -58,12 +58,10 @@ declare_lint_pass!(LetIfSeq => [USELESS_LET_IF_SEQ]);
 
 impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        let mut it = block.stmts.iter().peekable();
-        while let Some(stmt) = it.next() {
-            if let Some(expr) = it.peek()
-                && let hir::StmtKind::Let(local) = stmt.kind
+        for [stmt, next] in block.stmts.array_windows::<2>() {
+            if let hir::StmtKind::Let(local) = stmt.kind
                 && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
-                && let hir::StmtKind::Expr(if_) = expr.kind
+                && let hir::StmtKind::Expr(if_) = next.kind
                 && let hir::ExprKind::If(
                     hir::Expr {
                         kind: hir::ExprKind::DropTemps(cond),
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 9fd4f509aa4..8fa63f3e8fd 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -139,9 +139,9 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if matches!(local.source, LocalSource::Normal)
-            && !in_external_macro(cx.tcx.sess, local.span)
             && let PatKind::Wild = local.pat.kind
             && let Some(init) = local.init
+            && !in_external_macro(cx.tcx.sess, local.span)
         {
             let init_ty = cx.typeck_results().expr_ty(init);
             let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 593b29154b4..5a11702d7ce 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::source::snippet;
+use clippy_utils::is_from_proc_macro;
 use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
@@ -25,19 +25,14 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 
-impl LateLintPass<'_> for UnderscoreTyped {
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
-        if !in_external_macro(cx.tcx.sess, local.span)
-            && let Some(ty) = local.ty // Ensure that it has a type defined
+impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
+        if let Some(ty) = local.ty // Ensure that it has a type defined
             && let TyKind::Infer = &ty.kind // that type is '_'
             && local.span.eq_ctxt(ty.span)
+            && !in_external_macro(cx.tcx.sess, local.span)
+            && !is_from_proc_macro(cx, ty)
         {
-            // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized,
-            // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty`
-            if snippet(cx, ty.span, "_").trim() != "_" {
-                return;
-            }
-
             span_lint_and_help(
                 cx,
                 LET_WITH_TYPE_UNDERSCORE,
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 32fad0f02ce..c2dc26d6605 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -4,7 +4,9 @@
 #![feature(f128)]
 #![feature(f16)]
 #![feature(if_let_guard)]
+#![feature(is_sorted)]
 #![feature(iter_intersperse)]
+#![feature(iter_partition_in_place)]
 #![feature(let_chains)]
 #![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(never_type)]
@@ -90,8 +92,10 @@ mod bool_to_int_with_if;
 mod booleans;
 mod borrow_deref_ref;
 mod box_default;
+mod byte_char_slices;
 mod cargo;
 mod casts;
+mod cfg_not_test;
 mod checked_conversions;
 mod cognitive_complexity;
 mod collapsible_if;
@@ -212,6 +216,7 @@ mod manual_non_exhaustive;
 mod manual_range_patterns;
 mod manual_rem_euclid;
 mod manual_retain;
+mod manual_rotate;
 mod manual_slice_size_calculation;
 mod manual_string_new;
 mod manual_strip;
@@ -229,6 +234,7 @@ mod mismatching_type_param_order;
 mod missing_assert_message;
 mod missing_asserts_for_indexing;
 mod missing_const_for_fn;
+mod missing_const_for_thread_local;
 mod missing_doc;
 mod missing_enforced_import_rename;
 mod missing_fields_in_debug;
@@ -275,9 +281,9 @@ mod only_used_in_recursion;
 mod operators;
 mod option_env_unwrap;
 mod option_if_let_else;
-mod overflow_check_conditional;
 mod panic_in_result_fn;
 mod panic_unimplemented;
+mod panicking_overflow_checks;
 mod partial_pub_fields;
 mod partialeq_ne_impl;
 mod partialeq_to_none;
@@ -318,6 +324,7 @@ mod self_named_constructors;
 mod semicolon_block;
 mod semicolon_if_nothing_returned;
 mod serde_api;
+mod set_contains_or_insert;
 mod shadow;
 mod significant_drop_tightening;
 mod single_call_fn;
@@ -339,7 +346,6 @@ mod swap_ptr_to_ref;
 mod tabs_in_doc_comments;
 mod temporary_assignment;
 mod tests_outside_test_module;
-mod thread_local_initializer_can_be_made_const;
 mod to_digit_is_some;
 mod to_string_trait_impl;
 mod trailing_empty_array;
@@ -639,9 +645,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         });
         store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce));
         store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls));
-        store.register_late_pass(|_| {
-            Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new())
-        });
         store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
         store.register_late_pass(|_| {
             Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
@@ -788,7 +791,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     let format_args = format_args_storage.clone();
     store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(swap::Swap));
-    store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
+    store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks));
     store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
     store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names)));
     store.register_late_pass(move |_| {
@@ -1024,6 +1027,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
     store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
     store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate));
     store.register_late_pass(move |_| {
         Box::new(operators::Operators::new(
             verbose_bit_mask_threshold,
@@ -1153,9 +1157,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             behavior: pub_underscore_fields_behavior,
         })
     });
-    store.register_late_pass(move |_| {
-        Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv()))
-    });
+    store
+        .register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(msrv())));
     store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv())));
     store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl));
     store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations));
@@ -1171,6 +1174,9 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     });
     store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
     store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
+    store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
+    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`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index d2a140a36a8..7481543941a 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -233,11 +233,9 @@ impl_lint_pass!(LiteralDigitGrouping => [
 
 impl EarlyLintPass for LiteralDigitGrouping {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Lit(lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind
+            && !in_external_macro(cx.sess(), expr.span)
+        {
             self.check_lit(cx, lit, expr.span);
         }
     }
@@ -448,11 +446,9 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
 
 impl EarlyLintPass for DecimalLiteralRepresentation {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Lit(lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind
+            && !in_external_macro(cx.sess(), expr.span)
+        {
             self.check_lit(cx, lit, expr.span);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 24fc2b4faea..d9f6be6dc2b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -50,13 +50,10 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualBits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::MANUAL_BITS) {
-            return;
-        }
-
         if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind
             && let BinOpKind::Mul = &bin_op.node
             && !in_external_macro(cx.sess(), expr.span)
+            && self.msrv.meets(msrvs::MANUAL_BITS)
             && let ctxt = expr.span.ctxt()
             && left_expr.span.ctxt() == ctxt
             && right_expr.span.ctxt() == ctxt
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 89eea0b4456..03416ba96de 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -82,29 +82,26 @@ impl Variant {
 
 impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !in_external_macro(cx.sess(), expr.span)
-            && (
-                matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
-                    || cx.tcx.features().declared(sym!(const_float_classify))
-            ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
+        if let ExprKind::Binary(kind, lhs, rhs) = expr.kind
             && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
             && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
             // Checking all possible scenarios using a function would be a hopeless task, as we have
             // 16 possible alignments of constants/operands. For now, let's use `partition`.
-            && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
-                .into_iter()
-                .partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
-            && let [first, second] = &*operands
-            && let Some([const_1, const_2]) = constants
-                .into_iter()
-                .map(|i| constant(cx, cx.typeck_results(), i))
-                .collect::<Option<Vec<_>>>()
-                .as_deref()
+            && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
+            && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
+            && !in_external_macro(cx.sess(), expr.span)
+            && (
+                matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
+                    || 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)
             && 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
-            && (is_infinity(const_1) && is_neg_infinity(const_2)
-                || is_neg_infinity(const_1) && is_infinity(const_2))
+            && (is_infinity(&const_1) && is_neg_infinity(&const_2)
+                || is_neg_infinity(&const_1) && is_infinity(&const_2))
             && let Some(local_snippet) = snippet_opt(cx, first.span)
         {
             let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 03e4d668dd8..ebebdf679a8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -49,16 +49,14 @@ declare_clippy_lint! {
 
 impl<'tcx> QuestionMark {
     pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
-        if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
-            return;
-        }
-
         if let StmtKind::Let(local) = stmt.kind
             && let Some(init) = local.init
             && local.els.is_none()
             && local.ty.is_none()
             && init.span.eq_ctxt(stmt.span)
             && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
+            && self.msrv.meets(msrvs::LET_ELSE)
+            && !in_external_macro(cx.sess(), stmt.span)
         {
             match if_let_or_match {
                 IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
index 5732bdda7f2..8e8cdc3fb07 100644
--- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
@@ -47,13 +47,13 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]);
 
 impl LateLintPass<'_> for ManualMainSeparatorStr {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
-            && let (target, _) = peel_hir_expr_refs(expr)
-            && is_trait_method(cx, target, sym::ToString)
-            && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
+        let (target, _) = peel_hir_expr_refs(expr);
+        if let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
             && path.ident.name == sym::to_string
             && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
             && let Res::Def(DefKind::Const, receiver_def_id) = path.res
+            && is_trait_method(cx, target, sym::ToString)
+            && self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
             && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR)
             && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
             && ty.is_str()
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index d2ac0ad8363..73a505fd73f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -97,19 +97,15 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
 
 impl EarlyLintPass for ManualNonExhaustiveStruct {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
-        if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
-            return;
-        }
-
-        if let ast::ItemKind::Struct(variant_data, _) = &item.kind {
-            let (fields, delimiter) = match variant_data {
+        if let ast::ItemKind::Struct(variant_data, _) = &item.kind
+            && let (fields, delimiter) = match variant_data {
                 ast::VariantData::Struct { fields, .. } => (&**fields, '{'),
                 ast::VariantData::Tuple(fields, _) => (&**fields, '('),
                 ast::VariantData::Unit(_) => return,
-            };
-            if fields.len() <= 1 {
-                return;
             }
+            && fields.len() > 1
+            && self.msrv.meets(msrvs::NON_EXHAUSTIVE)
+        {
             let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
                 VisibilityKind::Public => None,
                 VisibilityKind::Inherited => Some(Ok(f)),
diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
index ec60de92c4b..07d4abbf5cd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -76,14 +76,11 @@ impl Num {
 
 impl LateLintPass<'_> for ManualRangePatterns {
     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) {
-        if in_external_macro(cx.sess(), pat.span) {
-            return;
-        }
-
         // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives
         // or at least one range
         if let PatKind::Or(pats) = pat.kind
             && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))
+            && !in_external_macro(cx.sess(), pat.span)
         {
             let mut min = Num::dummy(i128::MAX);
             let mut max = Num::dummy(i128::MIN);
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 ab9bca170cf..b518dc26937 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -48,35 +48,30 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::REM_EUCLID) {
-            return;
-        }
-
-        if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) {
-            return;
-        }
-
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
         // (x % c + c) % c
-        if let ExprKind::Binary(op1, expr1, right) = expr.kind
-            && op1.node == BinOpKind::Rem
+        if let ExprKind::Binary(rem_op, rem_lhs, rem_rhs) = expr.kind
+            && rem_op.node == BinOpKind::Rem
+            && let ExprKind::Binary(add_op, add_lhs, add_rhs) = rem_lhs.kind
+            && add_op.node == BinOpKind::Add
             && let ctxt = expr.span.ctxt()
-            && expr1.span.ctxt() == ctxt
-            && let Some(const1) = check_for_unsigned_int_constant(cx, right)
-            && let ExprKind::Binary(op2, left, right) = expr1.kind
-            && op2.node == BinOpKind::Add
-            && let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right)
-            && expr2.span.ctxt() == ctxt
-            && let ExprKind::Binary(op3, expr3, right) = expr2.kind
-            && op3.node == BinOpKind::Rem
-            && let Some(const3) = check_for_unsigned_int_constant(cx, right)
+            && rem_lhs.span.ctxt() == ctxt
+            && rem_rhs.span.ctxt() == ctxt
+            && add_lhs.span.ctxt() == ctxt
+            && 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))
+            && 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
+            && rem2_op.node == BinOpKind::Rem
+            && const1 == const2
+            && let Some(hir_id) = path_to_local(rem2_lhs)
+            && let Some(const3) = check_for_unsigned_int_constant(cx, rem2_rhs)
             // Also ensures the const is nonzero since zero can't be a divisor
-            && const1 == const2 && const2 == const3
-            && let Some(hir_id) = path_to_local(expr3)
-            && let Node::Pat(_) = cx.tcx.hir_node(hir_id)
+            && const2 == const3
+            && rem2_lhs.span.ctxt() == ctxt
+            && rem2_rhs.span.ctxt() == ctxt
         {
             // Apply only to params or locals with annotated types
             match cx.tcx.parent_hir_node(hir_id) {
@@ -91,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             };
 
             let mut app = Applicability::MachineApplicable;
-            let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0;
+            let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0;
             span_lint_and_sugg(
                 cx,
                 MANUAL_REM_EUCLID,
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 3ddb06a1e08..8f7b8abd0c3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -70,9 +70,8 @@ impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]);
 impl<'tcx> LateLintPass<'tcx> for ManualRetain {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if let Assign(left_expr, collect_expr, _) = &expr.kind
-            && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
+            && let hir::ExprKind::MethodCall(seg, target_expr, [], _) = &collect_expr.kind
             && seg.args.is_none()
-            && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
             && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/manual_rotate.rs b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
new file mode 100644
index 00000000000..a517a4d5075
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
@@ -0,0 +1,117 @@
+use std::fmt::Display;
+
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// It detects manual bit rotations that could be rewritten using standard
+    /// functions `rotate_left` or `rotate_right`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Calling the function better conveys the intent.
+    ///
+    /// ### Known issues
+    ///
+    /// Currently, the lint only catches shifts by constant amount.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x = 12345678_u32;
+    /// let _ = (x >> 8) | (x << 24);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x = 12345678_u32;
+    /// let _ = x.rotate_right(8);
+    /// ```
+    #[clippy::version = "1.81.0"]
+    pub MANUAL_ROTATE,
+    style,
+    "using bit shifts to rotate integers"
+}
+
+declare_lint_pass!(ManualRotate => [MANUAL_ROTATE]);
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum ShiftDirection {
+    Left,
+    Right,
+}
+
+impl Display for ShiftDirection {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(match self {
+            Self::Left => "rotate_left",
+            Self::Right => "rotate_right",
+        })
+    }
+}
+
+fn parse_shift<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> {
+    if let ExprKind::Binary(op, l, r) = expr.kind {
+        let dir = match op.node {
+            BinOpKind::Shl => ShiftDirection::Left,
+            BinOpKind::Shr => ShiftDirection::Right,
+            _ => return None,
+        };
+        let const_expr = constant(cx, cx.typeck_results(), r)?;
+        if let Constant::Int(shift) = const_expr {
+            return Some((dir, shift, l));
+        }
+    }
+    None
+}
+
+impl LateLintPass<'_> for ManualRotate {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if let ExprKind::Binary(op, l, r) = expr.kind
+            && let BinOpKind::Add | BinOpKind::BitOr = op.node
+            && let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l)
+            && let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r)
+        {
+            if l_shift_dir == r_shift_dir {
+                return;
+            }
+            if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) {
+                return;
+            }
+            let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() {
+                ty::Int(itype) => itype.bit_width(),
+                ty::Uint(itype) => itype.bit_width(),
+                _ => return,
+            }) else {
+                return;
+            };
+            if l_amount + r_amount == u128::from(bit_width) {
+                let (shift_function, amount) = if l_amount < r_amount {
+                    (l_shift_dir, l_amount)
+                } else {
+                    (r_shift_dir, r_amount)
+                };
+                let mut applicability = Applicability::MachineApplicable;
+                let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_par();
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_ROTATE,
+                    expr.span,
+                    "there is no need to manually implement bit rotation",
+                    "this expression can be rewritten as",
+                    format!("{expr_sugg}.{shift_function}({amount})"),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
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 1de686dbcb5..429ee2637c2 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
@@ -40,11 +40,11 @@ declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]
 
 impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        // Does not apply inside const because size_of_val is not cost in stable.
-        if !in_constant(cx, expr.hir_id)
-            && let ExprKind::Binary(ref op, left, right) = expr.kind
+        if let ExprKind::Binary(ref op, left, right) = expr.kind
             && 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)
             && 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 45af9f07718..6a523ad1564 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -66,14 +66,11 @@ enum StripKind {
 
 impl<'tcx> LateLintPass<'tcx> for ManualStrip {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
-            return;
-        }
-
         if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
             && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind
-            && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
             && let ExprKind::Path(target_path) = &target_arg.kind
+            && self.msrv.meets(msrvs::STR_STRIP_PREFIX)
+            && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
         {
             let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
                 StripKind::Prefix
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 58b2ebebbf0..f1acc4b2174 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
@@ -172,11 +172,10 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp
 
 impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
-            return;
-        }
-        // Call handle only if the expression is `if let` or `match`
-        if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) {
+        if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr)
+            && !expr.span.from_expansion()
+            && !in_constant(cx, expr.hir_id)
+        {
             handle(cx, if_let_or_match, expr);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 9db04b615be..2db71b1f7a3 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -253,14 +253,11 @@ fn lint_map_unit_fn(
 
 impl<'tcx> LateLintPass<'tcx> for MapUnit {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
-        if stmt.span.from_expansion() {
-            return;
-        }
-
-        if let hir::StmtKind::Semi(expr) = stmt.kind {
-            if let Some(arglists) = method_chain_args(expr, &["map"]) {
-                lint_map_unit_fn(cx, stmt, expr, arglists[0]);
-            }
+        if let hir::StmtKind::Semi(expr) = stmt.kind
+            && !stmt.span.from_expansion()
+            && let Some(arglists) = method_chain_args(expr, &["map"])
+        {
+            lint_map_unit_fn(cx, stmt, expr, arglists[0]);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index bf7156cc53e..22a299ae3d8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1019,6 +1019,7 @@ impl_lint_pass!(Matches => [
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
+    #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) {
             return;
@@ -1037,7 +1038,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 return;
             }
             if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) {
-                significant_drop_in_scrutinee::check(cx, expr, ex, arms, source);
+                significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source);
             }
 
             collapsible_match::check_match(cx, arms, &self.msrv);
@@ -1084,6 +1085,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
             }
         } else if let Some(if_let) = higher::IfLet::hir(cx, expr) {
             collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv);
+            significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else);
             if !from_expansion {
                 if let Some(else_expr) = if_let.if_else {
                     if self.msrv.meets(msrvs::MATCHES_MACRO) {
@@ -1126,8 +1128,13 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 );
                 needless_match::check_if_let(cx, expr, &if_let);
             }
-        } else if !from_expansion {
-            redundant_pattern_match::check(cx, expr);
+        } else {
+            if let Some(while_let) = higher::WhileLet::hir(expr) {
+                significant_drop_in_scrutinee::check_while_let(cx, expr, while_let.let_expr, while_let.if_then);
+            }
+            if !from_expansion {
+                redundant_pattern_match::check(cx, expr);
+            }
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 2f72e59834f..9047c9627d9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -16,7 +16,7 @@ use rustc_span::Span;
 
 use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
 
-pub(super) fn check<'tcx>(
+pub(super) fn check_match<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
     scrutinee: &'tcx Expr<'_>,
@@ -27,10 +27,89 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    let (suggestions, message) = has_significant_drop_in_scrutinee(cx, scrutinee, source);
+    let scrutinee = match (source, &scrutinee.kind) {
+        (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e,
+        _ => scrutinee,
+    };
+
+    let message = if source == MatchSource::Normal {
+        "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression"
+    } else {
+        "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression"
+    };
+
+    let arms = arms.iter().map(|arm| arm.body).collect::<Vec<_>>();
+
+    check(cx, expr, scrutinee, &arms, message, Suggestion::Emit);
+}
+
+pub(super) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    if_then: &'tcx Expr<'_>,
+    if_else: Option<&'tcx Expr<'_>>,
+) {
+    if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) {
+        return;
+    }
+
+    let message =
+        "temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression";
+
+    if let Some(if_else) = if_else {
+        check(cx, expr, scrutinee, &[if_then, if_else], message, Suggestion::Emit);
+    } else {
+        check(cx, expr, scrutinee, &[if_then], message, Suggestion::Emit);
+    }
+}
+
+pub(super) fn check_while_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    body: &'tcx Expr<'_>,
+) {
+    if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) {
+        return;
+    }
+
+    check(
+        cx,
+        expr,
+        scrutinee,
+        &[body],
+        "temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression",
+        // Don't emit wrong suggestions: We cannot fix the significant drop in the `while let` scrutinee by simply
+        // moving it out. We need to change the `while` to a `loop` instead.
+        Suggestion::DontEmit,
+    );
+}
+
+#[derive(Copy, Clone, Debug)]
+enum Suggestion {
+    Emit,
+    DontEmit,
+}
+
+fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    arms: &[&'tcx Expr<'_>],
+    message: &'static str,
+    sugg: Suggestion,
+) {
+    let mut helper = SigDropHelper::new(cx);
+    let suggestions = helper.find_sig_drop(scrutinee);
+
     for found in suggestions {
         span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| {
-            set_diagnostic(diag, cx, expr, found);
+            match sugg {
+                Suggestion::Emit => set_suggestion(diag, cx, expr, found),
+                Suggestion::DontEmit => (),
+            }
+
             let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None);
             diag.span_label(s, "temporary lives until here");
             for span in has_significant_drop_in_arms(cx, arms) {
@@ -41,7 +120,7 @@ pub(super) fn check<'tcx>(
     }
 }
 
-fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
+fn set_suggestion<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
     let original = snippet(cx, found.found_span, "..");
     let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0));
 
@@ -79,26 +158,6 @@ fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &
     );
 }
 
-/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that
-/// may have a surprising lifetime.
-fn has_significant_drop_in_scrutinee<'tcx>(
-    cx: &LateContext<'tcx>,
-    scrutinee: &'tcx Expr<'tcx>,
-    source: MatchSource,
-) -> (Vec<FoundSigDrop>, &'static str) {
-    let mut helper = SigDropHelper::new(cx);
-    let scrutinee = match (source, &scrutinee.kind) {
-        (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e,
-        _ => scrutinee,
-    };
-    let message = if source == MatchSource::Normal {
-        "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression"
-    } else {
-        "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression"
-    };
-    (helper.find_sig_drop(scrutinee), message)
-}
-
 struct SigDropChecker<'a, 'tcx> {
     seen_types: FxHashSet<Ty<'tcx>>,
     cx: &'a LateContext<'tcx>,
@@ -428,10 +487,10 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> {
     }
 }
 
-fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
+fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxHashSet<Span> {
     let mut helper = ArmSigDropHelper::new(cx);
     for arm in arms {
-        helper.visit_expr(arm.body);
+        helper.visit_expr(arm);
     }
     helper.found_sig_drop_spans
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index e3ce64c246a..cac2e11f591 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -167,14 +167,12 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
             } else {
                 edits.extend(addr_of_edits);
             }
-            edits.push((
-                name_span,
-                String::from(match name {
-                    "map" => "inspect",
-                    "map_err" => "inspect_err",
-                    _ => return,
-                }),
-            ));
+            let edit = match name {
+                "map" => "inspect",
+                "map_err" => "inspect_err",
+                _ => return,
+            };
+            edits.push((name_span, edit.to_string()));
             edits.push((
                 final_expr
                     .span
@@ -187,9 +185,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
             } else {
                 Applicability::MachineApplicable
             };
-            span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| {
-                diag.multipart_suggestion("try", edits, app);
-            });
+            span_lint_and_then(
+                cx,
+                MANUAL_INSPECT,
+                name_span,
+                format!("using `{name}` over `{edit}`"),
+                |diag| {
+                    diag.multipart_suggestion("try", edits, app);
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 1408f454820..a846552cddf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -628,12 +628,11 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
-    /// `_.or_else(|x| Err(y))`.
+    /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))`
+    /// or `_.or_else(|x| Err(y))`.
     ///
     /// ### Why is this bad?
-    /// Readability, this can be written more concisely as
-    /// `_.map(|x| y)` or `_.map_err(|x| y)`.
+    /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| y)`.
     ///
     /// ### Example
     /// ```no_run
@@ -4121,7 +4120,7 @@ declare_clippy_lint! {
     /// ```no_run
     /// let x = Some(0).inspect(|x| println!("{x}"));
     /// ```
-    #[clippy::version = "1.78.0"]
+    #[clippy::version = "1.81.0"]
     pub MANUAL_INSPECT,
     complexity,
     "use of `map` returning the original item"
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 ae9aa83efd6..5d899415d77 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
@@ -1,13 +1,15 @@
 use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_opt;
+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::visitors::find_all_ret_expressions;
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
+use clippy_utils::{
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty,
+};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -52,6 +54,9 @@ pub fn check<'tcx>(
             if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) {
                 return;
             }
+            if check_string_from_utf8(cx, expr, receiver) {
+                return;
+            }
             check_other_call_arg(cx, expr, method_name, receiver);
         }
     } else {
@@ -240,6 +245,65 @@ fn check_into_iter_call_arg(
     false
 }
 
+/// Checks for `&String::from_utf8(bytes.{to_vec,to_owned,...}()).unwrap()` coercing to `&str`,
+/// which can be written as just `std::str::from_utf8(bytes).unwrap()`.
+fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, receiver: &'tcx Expr<'tcx>) -> bool {
+    if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr)
+        && !arg.span.from_expansion()
+        && let ExprKind::Call(callee, _) = call.kind
+        && fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8))
+        && let Some(unwrap_call) = get_parent_expr(cx, call)
+        && let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind
+        && matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect)
+        && let Some(ref_string) = get_parent_expr(cx, unwrap_call)
+        && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = ref_string.kind
+        && let adjusted_ty = cx.typeck_results().expr_ty_adjusted(ref_string)
+        // `&...` creates a `&String`, so only actually lint if this coerces to a `&str`
+        && matches!(adjusted_ty.kind(), ty::Ref(_, ty, _) if ty.is_str())
+    {
+        span_lint_and_then(
+            cx,
+            UNNECESSARY_TO_OWNED,
+            ref_string.span,
+            "allocating a new `String` only to create a temporary `&str` from it",
+            |diag| {
+                let arg_suggestion = format!(
+                    "{borrow}{recv_snippet}",
+                    recv_snippet = snippet(cx, receiver.span.source_callsite(), ".."),
+                    borrow = if cx.typeck_results().expr_ty(receiver).is_ref() {
+                        ""
+                    } else {
+                        // If not already a reference, prefix with a borrow so that it can coerce to one
+                        "&"
+                    }
+                );
+
+                diag.multipart_suggestion(
+                    "convert from `&[u8]` to `&str` directly",
+                    vec![
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //   ^^^^^^^^^^^^^^^^^
+                        (callee.span, "core::str::from_utf8".into()),
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //  ^
+                        (
+                            ref_string.span.shrink_to_lo().to(unwrap_call.span.shrink_to_lo()),
+                            String::new(),
+                        ),
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //                     ^^^^^^^^^^^^^^
+                        (arg.span, arg_suggestion),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            },
+        );
+        true
+    } else {
+        false
+    }
+}
+
 /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
 /// call of a `to_owned`-like function is unnecessary.
 fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
index 516b8984ad7..5b0bd0f716a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
-use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
+use clippy_utils::{is_in_test, is_lint_allowed};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, Lint};
 use rustc_middle::ty;
@@ -61,7 +61,7 @@ pub(super) fn check(
 
     let method_suffix = if is_err { "_err" } else { "" };
 
-    if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
+    if allow_unwrap_in_tests && is_in_test(cx.tcx, expr.hir_id) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index fca626fa5c3..c3fbca1d560 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
-use std::cmp::Ordering;
+use std::cmp::Ordering::{Equal, Greater, Less};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,26 +36,21 @@ declare_lint_pass!(MinMaxPass => [MIN_MAX]);
 
 impl<'tcx> LateLintPass<'tcx> for MinMaxPass {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) {
-            if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) {
-                if outer_max == inner_max {
-                    return;
-                }
-                match (
-                    outer_max,
-                    Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c),
-                ) {
-                    (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
-                    _ => {
-                        span_lint(
-                            cx,
-                            MIN_MAX,
-                            expr.span,
-                            "this `min`/`max` combination leads to constant result",
-                        );
-                    },
-                }
-            }
+        if let Some((outer_max, outer_c, oe)) = min_max(cx, expr)
+            && let Some((inner_max, inner_c, ie)) = min_max(cx, oe)
+            && outer_max != inner_max
+            && let Some(ord) = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c)
+            && matches!(
+                (outer_max, ord),
+                (MinMax::Max, Equal | Greater) | (MinMax::Min, Equal | Less)
+            )
+        {
+            span_lint(
+                cx,
+                MIN_MAX,
+                expr.span,
+                "this `min`/`max` combination leads to constant result",
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index f3f9bf11a61..32c8731c537 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats,
-    last_path_segment, SpanlessEq,
+    fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment,
+    SpanlessEq,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if in_external_macro(cx.sess(), expr.span)
             || expr.span.desugaring_kind().is_some()
-            || any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+            || in_automatically_derived(cx.tcx, expr.hir_id)
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index fedcfd11fdc..4cba13a05c2 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -364,8 +364,8 @@ declare_lint_pass!(MiscEarlyLints => [
 ]);
 
 impl EarlyLintPass for MiscEarlyLints {
-    fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
-        for param in &gen.params {
+    fn check_generics(&mut self, cx: &EarlyContext<'_>, generics: &Generics) {
+        for param in &generics.params {
             builtin_type_shadow::check(cx, param);
         }
     }
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 dd98352da86..935ed48dacc 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn};
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage {
         };
 
         // This lint would be very noisy in tests, so just ignore if we're in test context
-        if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) {
+        if is_in_test(cx.tcx, expr.hir_id) {
             return;
         }
 
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 bb0d714a31f..ed5f46ddc8d 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
@@ -8,9 +8,11 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -115,7 +117,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
                     .iter()
                     .any(|param| matches!(param.kind, GenericParamKind::Const { .. }));
 
-                if already_const(header) || has_const_generic_params {
+                if already_const(header)
+                    || has_const_generic_params
+                    || !could_be_const_with_abi(cx, &self.msrv, header.abi)
+                {
                     return;
                 }
             },
@@ -127,6 +132,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             FnKind::Closure => return,
         }
 
+        if fn_inputs_has_impl_trait_ty(cx, def_id) {
+            return;
+        }
+
         let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
 
         // Const fns are not allowed as methods in a trait.
@@ -171,3 +180,25 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 fn already_const(header: hir::FnHeader) -> bool {
     header.constness == Constness::Const
 }
+
+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
+        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,
+    }
+}
+
+/// Return `true` when the given `def_id` is a function that has `impl Trait` ty as one of
+/// its parameter types.
+fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    let inputs = cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder();
+    inputs.iter().any(|input| {
+        matches!(
+            input.kind(),
+            ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait()
+        )
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs
index 4af3ee74d0e..ab1b4aa3dee 100644
--- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs
@@ -39,23 +39,23 @@ declare_clippy_lint! {
     /// }
     /// ```
     #[clippy::version = "1.77.0"]
-    pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
+    pub MISSING_CONST_FOR_THREAD_LOCAL,
     perf,
     "suggest using `const` in `thread_local!` macro"
 }
 
-pub struct ThreadLocalInitializerCanBeMadeConst {
+pub struct MissingConstForThreadLocal {
     msrv: Msrv,
 }
 
-impl ThreadLocalInitializerCanBeMadeConst {
+impl MissingConstForThreadLocal {
     #[must_use]
     pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
 
-impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST]);
+impl_lint_pass!(MissingConstForThreadLocal => [MISSING_CONST_FOR_THREAD_LOCAL]);
 
 #[inline]
 fn is_thread_local_initializer(
@@ -102,7 +102,7 @@ fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id
     false
 }
 
-impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
+impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
@@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
         local_defid: rustc_span::def_id::LocalDefId,
     ) {
         let defid = local_defid.to_def_id();
-        if self.msrv.meets(msrvs::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST)
+        if self.msrv.meets(msrvs::THREAD_LOCAL_CONST_INIT)
             && is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false)
             // Some implementations of `thread_local!` include an initializer fn.
             // In the case of a const initializer, the init fn is also const,
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
         {
             span_lint_and_sugg(
                 cx,
-                THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
+                MISSING_CONST_FOR_THREAD_LOCAL,
                 unpeeled.span,
                 "initializer for `thread_local` value can be made `const`",
                 "replace with",
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 57ba0da5331..5ffd41d78e0 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -27,7 +27,7 @@ declare_clippy_lint! {
     /// Check if a `&mut` function argument is actually used mutably.
     ///
     /// Be careful if the function is publicly reexported as it would break compatibility with
-    /// users of this function.
+    /// users of this function, when the users pass this function as an argument.
     ///
     /// ### Why is this bad?
     /// Less `mut` means less fights with the borrow checker. It can also lead to more
@@ -138,6 +138,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             return;
         }
 
+        if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id) {
+            return;
+        }
+
         let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id);
         let is_async = match kind {
             FnKind::ItemFn(.., header) => {
@@ -262,9 +266,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             .iter()
             .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id))
         {
-            let show_semver_warning =
-                self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);
-
             let mut is_cfged = None;
             for input in unused {
                 // If the argument is never used mutably, we emit the warning.
@@ -284,7 +285,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
                                 format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),),
                                 Applicability::Unspecified,
                             );
-                            if show_semver_warning {
+                            if cx.effective_visibilities.is_exported(*fn_def_id) {
                                 diag.warn("changing this function will impact semver compatibility");
                             }
                             if *is_cfged {
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 87f886b1128..0ecfa7baa72 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::has_drop;
-use clippy_utils::{any_parent_is_automatically_derived, is_lint_allowed, path_to_local, peel_blocks};
+use clippy_utils::{
+    in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks,
+};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
@@ -185,7 +187,7 @@ impl NoEffect {
                 && has_no_effect(cx, init)
                 && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
                 && ident.name.to_ident_string().starts_with('_')
-                && !any_parent_is_automatically_derived(cx.tcx, local.hir_id)
+                && !in_automatically_derived(cx.tcx, local.hir_id)
             {
                 if let Some(l) = self.local_bindings.last_mut() {
                     l.push(hir_id);
@@ -258,13 +260,16 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 
 fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if let StmtKind::Semi(expr) = stmt.kind
+        && !in_external_macro(cx.sess(), stmt.span)
         && let ctxt = stmt.span.ctxt()
         && expr.span.ctxt() == ctxt
         && let Some(reduced) = reduce_expression(cx, expr)
-        && !in_external_macro(cx.sess(), stmt.span)
         && reduced.iter().all(|e| e.span.ctxt() == ctxt)
     {
         if let ExprKind::Index(..) = &expr.kind {
+            if is_inside_always_const_context(cx.tcx, expr.hir_id) {
+                return;
+            }
             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)
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 faab79de9d3..0e5b440c50f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -57,7 +57,6 @@ pub(crate) fn check<'tcx>(
                     Applicability::HasPlaceholders, // snippet
                 );
             }
-            diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`");
         });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 48a442705b2..59834781a58 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -242,6 +242,13 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// if (x | 1 > 3) {  }
     /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```no_run
+    /// # let x = 1;
+    /// if (x >= 2) {  }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub INEFFECTIVE_BIT_MASK,
     correctness,
@@ -265,6 +272,13 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// if x & 0b1111 == 0 { }
     /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```no_run
+    /// # let x: i32 = 1;
+    /// if x.trailing_zeros() > 4 { }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub VERBOSE_BIT_MASK,
     pedantic,
@@ -560,74 +574,128 @@ declare_clippy_lint! {
     /// implement equality for a type involving floats).
     ///
     /// ### Why is this bad?
-    /// Floating point calculations are usually imprecise, so
-    /// asking if two values are *exactly* equal is asking for trouble. For a good
-    /// guide on what to do, see [the floating point
-    /// guide](http://www.floating-point-gui.de/errors/comparison).
+    /// Floating point calculations are usually imprecise, so asking if two values are *exactly*
+    /// equal is asking for trouble because arriving at the same logical result via different
+    /// routes (e.g. calculation versus constant) may yield different values.
     ///
     /// ### Example
+    ///
     /// ```no_run
-    /// let x = 1.2331f64;
-    /// let y = 1.2332f64;
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// let y = 1000.3; // Expected value.
     ///
-    /// if y == 1.23f64 { }
-    /// if y != x {} // where both are floats
+    /// // Actual value: 1000.3000000000001
+    /// println!("{x}");
+    ///
+    /// let are_equal = x == y;
+    /// println!("{are_equal}"); // false
     /// ```
     ///
-    /// Use instead:
+    /// The correct way to compare floating point numbers is to define an allowed error margin. This
+    /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there
+    /// are two cases:
+    ///
+    /// 1. If your values are in a known range and you can define a threshold for "close enough to
+    ///    be equal", it may be appropriate to define an absolute error margin. For example, if your
+    ///    data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough".
+    /// 1. If your code is more general and you do not know the range of values, you should use a
+    ///    relative error margin, accepting e.g. 0.1% of error regardless of specific values.
+    ///
+    /// For the scenario where you can define a meaningful absolute error margin, consider using:
+    ///
     /// ```no_run
-    /// # let x = 1.2331f64;
-    /// # let y = 1.2332f64;
-    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
-    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
-    /// // let error_margin = std::f64::EPSILON;
-    /// if (y - 1.23f64).abs() < error_margin { }
-    /// if (y - x).abs() > error_margin { }
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// let y = 1000.3; // Expected value.
+    ///
+    /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1;
+    /// let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM;
+    /// println!("{within_tolerance}"); // true
     /// ```
+    ///
+    /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is
+    /// a different use of the term that is not suitable for floating point equality comparison.
+    /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`.
+    ///
+    /// For the scenario where no meaningful absolute error can be defined, refer to
+    /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison)
+    /// for a reference implementation of relative error based comparison of floating point values.
+    /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust.
     #[clippy::version = "pre 1.29.0"]
     pub FLOAT_CMP,
     pedantic,
-    "using `==` or `!=` on float values instead of comparing difference with an epsilon"
+    "using `==` or `!=` on float values instead of comparing difference with an allowed error"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for (in-)equality comparisons on floating-point
-    /// value and constant, except in functions called `*eq*` (which probably
+    /// Checks for (in-)equality comparisons on constant floating-point
+    /// values (apart from zero), except in functions called `*eq*` (which probably
     /// implement equality for a type involving floats).
     ///
     /// ### Why restrict this?
-    /// Floating point calculations are usually imprecise, so
-    /// asking if two values are *exactly* equal is asking for trouble. For a good
-    /// guide on what to do, see [the floating point
-    /// guide](http://www.floating-point-gui.de/errors/comparison).
+    /// Floating point calculations are usually imprecise, so asking if two values are *exactly*
+    /// equal is asking for trouble because arriving at the same logical result via different
+    /// routes (e.g. calculation versus constant) may yield different values.
     ///
     /// ### Example
+    ///
     /// ```no_run
-    /// let x: f64 = 1.0;
-    /// const ONE: f64 = 1.00;
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// const Y: f64 = 1000.3; // Expected value.
+    ///
+    /// // Actual value: 1000.3000000000001
+    /// println!("{x}");
     ///
-    /// if x == ONE { } // where both are floats
+    /// let are_equal = x == Y;
+    /// println!("{are_equal}"); // false
     /// ```
     ///
-    /// Use instead:
+    /// The correct way to compare floating point numbers is to define an allowed error margin. This
+    /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there
+    /// are two cases:
+    ///
+    /// 1. If your values are in a known range and you can define a threshold for "close enough to
+    ///    be equal", it may be appropriate to define an absolute error margin. For example, if your
+    ///    data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough".
+    /// 1. If your code is more general and you do not know the range of values, you should use a
+    ///    relative error margin, accepting e.g. 0.1% of error regardless of specific values.
+    ///
+    /// For the scenario where you can define a meaningful absolute error margin, consider using:
+    ///
     /// ```no_run
-    /// # let x: f64 = 1.0;
-    /// # const ONE: f64 = 1.00;
-    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
-    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
-    /// // let error_margin = std::f64::EPSILON;
-    /// if (x - ONE).abs() < error_margin { }
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// const Y: f64 = 1000.3; // Expected value.
+    ///
+    /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1;
+    /// let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM;
+    /// println!("{within_tolerance}"); // true
     /// ```
+    ///
+    /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is
+    /// a different use of the term that is not suitable for floating point equality comparison.
+    /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`.
+    ///
+    /// For the scenario where no meaningful absolute error can be defined, refer to
+    /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison)
+    /// for a reference implementation of relative error based comparison of floating point values.
+    /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust.
     #[clippy::version = "pre 1.29.0"]
     pub FLOAT_CMP_CONST,
     restriction,
-    "using `==` or `!=` on float constants instead of comparing difference with an epsilon"
+    "using `==` or `!=` on float constants instead of comparing difference with an allowed error"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for getting the remainder of a division by one or minus
+    /// Checks for getting the remainder of integer division by one or minus
     /// one.
     ///
     /// ### Why is this bad?
@@ -646,7 +714,7 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub MODULO_ONE,
     correctness,
-    "taking a number modulo +/-1, which can either panic/overflow or always returns 0"
+    "taking an integer modulo +/-1, which can either panic/overflow or always returns 0"
 }
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
deleted file mode 100644
index de789879331..00000000000
--- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::SpanlessEq;
-use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Detects classic underflow/overflow checks.
-    ///
-    /// ### Why is this bad?
-    /// Most classic C underflow/overflow checks will fail in
-    /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// # let a = 1;
-    /// # let b = 2;
-    /// a + b < a;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub OVERFLOW_CHECK_CONDITIONAL,
-    complexity,
-    "overflow checks inspired by C which are likely to panic"
-}
-
-declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]);
-
-const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust";
-const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust";
-
-impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
-    // a + b < a, a > a + b, a < a - b, a - b > a
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r);
-        if let ExprKind::Binary(ref op, first, second) = expr.kind
-            && let ExprKind::Binary(ref op2, ident1, ident2) = first.kind
-            && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind
-            && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind
-            && let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind
-            && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]))
-            && cx.typeck_results().expr_ty(ident1).is_integral()
-            && cx.typeck_results().expr_ty(ident2).is_integral()
-        {
-            if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
-            }
-            if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
-            }
-        }
-
-        if let ExprKind::Binary(ref op, first, second) = expr.kind
-            && let ExprKind::Binary(ref op2, ident1, ident2) = second.kind
-            && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind
-            && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind
-            && let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind
-            && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]))
-            && cx.typeck_results().expr_ty(ident1).is_integral()
-            && cx.typeck_results().expr_ty(ident2).is_integral()
-        {
-            if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
-            }
-            if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
-            }
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
new file mode 100644
index 00000000000..7f100a746d5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::eq_expr_value;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects C-style underflow/overflow checks.
+    ///
+    /// ### Why is this bad?
+    /// These checks will, by default, panic in debug builds rather than check
+    /// whether the operation caused an overflow.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a + b < a {
+    ///     // handle overflow
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a.checked_add(b).is_none() {
+    ///     // handle overflow
+    /// }
+    /// ```
+    ///
+    /// Or:
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a.overflowing_add(b).1 {
+    ///     // handle overflow
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub PANICKING_OVERFLOW_CHECKS,
+    correctness,
+    "overflow checks which will panic in debug mode"
+}
+
+declare_lint_pass!(PanickingOverflowChecks => [PANICKING_OVERFLOW_CHECKS]);
+
+impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks {
+    // a + b < a, a > a + b, a < a - b, a - b > a
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Binary(op, lhs, rhs) = expr.kind
+            && let (lt, gt) = match op.node {
+                BinOpKind::Lt => (lhs, rhs),
+                BinOpKind::Gt => (rhs, lhs),
+                _ => return,
+            }
+            && let ctxt = expr.span.ctxt()
+            && let (op_lhs, op_rhs, other, commutative) = match (&lt.kind, &gt.kind) {
+                (&ExprKind::Binary(op, lhs, rhs), _) if op.node == BinOpKind::Add && ctxt == lt.span.ctxt() => {
+                    (lhs, rhs, gt, true)
+                },
+                (_, &ExprKind::Binary(op, lhs, rhs)) if op.node == BinOpKind::Sub && ctxt == gt.span.ctxt() => {
+                    (lhs, rhs, lt, false)
+                },
+                _ => return,
+            }
+            && let typeck = cx.typeck_results()
+            && let ty = typeck.expr_ty(op_lhs)
+            && matches!(ty.kind(), ty::Uint(_))
+            && ty == typeck.expr_ty(op_rhs)
+            && ty == typeck.expr_ty(other)
+            && !in_external_macro(cx.tcx.sess, expr.span)
+            && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other)))
+        {
+            span_lint(
+                cx,
+                PANICKING_OVERFLOW_CHECKS,
+                expr.span,
+                "you are trying to use classic C overflow conditions that will fail in Rust",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 85979903b58..8e999f3e89a 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -26,12 +26,14 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("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"),
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index c11da3147ef..8ced47b48a4 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -7,6 +7,7 @@ use clippy_utils::{
     path_to_local_id, span_contains_cfg, span_find_starting_semi,
 };
 use core::ops::ControlFlow;
+use rustc_ast::NestedMetaItem;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::LangItem::ResultErr;
@@ -14,13 +15,13 @@ use rustc_hir::{
     Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
     StmtKind,
 };
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{BytePos, Pos, Span};
+use rustc_span::{sym, BytePos, Pos, Span};
 use std::borrow::Cow;
 use std::fmt::Display;
 
@@ -80,6 +81,9 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NEEDLESS_RETURN,
+    // This lint requires some special handling in `check_final_expr` for `#[expect]`.
+    // This handling needs to be updated if the group gets changed. This should also
+    // be caught by tests.
     style,
     "using a return statement like `return expr;` where an expression would suffice"
 }
@@ -91,6 +95,9 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// The `return` is unnecessary.
     ///
+    /// Returns may be used to add attributes to the return expression. Return
+    /// statements with attributes are therefore be accepted by this lint.
+    ///
     /// ### Example
     /// ```rust,ignore
     /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
@@ -377,13 +384,39 @@ fn check_final_expr<'tcx>(
                 }
             };
 
-            if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
-                return;
-            }
             let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
             if borrows {
                 return;
             }
+            if ret_span.from_expansion() {
+                return;
+            }
+
+            // 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)
+            match cx.tcx.hir().attrs(expr.hir_id) {
+                [] => {},
+                [attr] => {
+                    if matches!(Level::from_attr(attr), Some(Level::Expect(_)))
+                        && let metas = attr.meta_item_list()
+                        && let Some(lst) = metas
+                        && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice()
+                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                        && tool.ident.name == sym::clippy
+                        && matches!(
+                            lint_name.ident.name.as_str(),
+                            "needless_return" | "style" | "all" | "warnings"
+                        )
+                    {
+                        // This is an expectation of the `needless_return` lint
+                    } else {
+                        return;
+                    }
+                },
+                _ => return,
+            }
 
             emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id);
         },
@@ -415,10 +448,6 @@ fn emit_return_lint(
     replacement: &RetReplacement<'_>,
     at: HirId,
 ) {
-    if ret_span.from_expansion() {
-        return;
-    }
-
     span_lint_hir_and_then(
         cx,
         NEEDLESS_RETURN,
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 8fdd19c549f..508f3ae6def 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -12,7 +12,7 @@ use std::collections::{BTreeMap, BTreeSet};
 declare_clippy_lint! {
     /// ### What it does
     /// It lints if a struct has two methods with the same name:
-    /// one from a trait, another not from trait.
+    /// one from a trait, another not from a trait.
     ///
     /// ### Why restrict this?
     /// Confusing.
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
new file mode 100644
index 00000000000..5e65b9fa517
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
@@ -0,0 +1,125 @@
+use std::ops::ControlFlow;
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq};
+use rustc_hir::{Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::symbol::Symbol;
+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`.
+    ///
+    /// ### Why is this bad?
+    /// Using just `insert` and checking the returned `bool` is more efficient.
+    ///
+    /// ### Known problems
+    /// In case the value that wants to be inserted is borrowed and also expensive or impossible
+    /// to clone. In such a scenario, the developer might want to check with `contains` before inserting,
+    /// to avoid the clone. In this case, it will report a false positive.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// let mut set = HashSet::new();
+    /// let value = 5;
+    /// if !set.contains(&value) {
+    ///     set.insert(value);
+    ///     println!("inserted {value:?}");
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// let mut set = HashSet::new();
+    /// let value = 5;
+    /// if set.insert(&value) {
+    ///     println!("inserted {value:?}");
+    /// }
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub SET_CONTAINS_OR_INSERT,
+    nursery,
+    "call to `HashSet::contains` followed by `HashSet::insert`"
+}
+
+declare_lint_pass!(HashsetInsertAfterContains => [SET_CONTAINS_OR_INSERT]);
+
+impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !expr.span.from_expansion()
+            && let Some(higher::If {
+                cond: cond_expr,
+                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(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`",
+            );
+        }
+    }
+}
+
+struct OpExpr<'tcx> {
+    receiver: &'tcx Expr<'tcx>,
+    value: &'tcx Expr<'tcx>,
+    span: Span,
+}
+
+fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol: Symbol) -> Option<OpExpr<'tcx>> {
+    let expr = peel_hir_expr_while(expr, |e| {
+        if let ExprKind::Unary(UnOp::Not, e) = e.kind {
+            Some(e)
+        } else {
+            None
+        }
+    });
+
+    if let ExprKind::MethodCall(path, receiver, [value], span) = expr.kind {
+        let value = value.peel_borrows();
+        let value = peel_hir_expr_while(value, |e| {
+            if let ExprKind::Unary(UnOp::Deref, e) = e.kind {
+                Some(e)
+            } else {
+                None
+            }
+        });
+        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 });
+        }
+    }
+    None
+}
+
+fn find_insert_calls<'tcx>(
+    cx: &LateContext<'tcx>,
+    contains_expr: &OpExpr<'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))
+            && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver)
+            && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value)
+        {
+            ControlFlow::Break(insert_expr)
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index c05cd9ed593..07390d6f430 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -102,9 +102,9 @@ impl TraitBounds {
 impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]);
 
 impl<'tcx> LateLintPass<'tcx> for TraitBounds {
-    fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
-        self.check_type_repetition(cx, gen);
-        check_trait_bound_duplication(cx, gen);
+    fn check_generics(&mut self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) {
+        self.check_type_repetition(cx, generics);
+        check_trait_bound_duplication(cx, generics);
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
@@ -238,7 +238,7 @@ impl TraitBounds {
     }
 
     #[allow(clippy::mutable_key_type)]
-    fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
+    fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) {
         struct SpanlessTy<'cx, 'tcx> {
             ty: &'tcx Ty<'tcx>,
             cx: &'cx LateContext<'tcx>,
@@ -258,12 +258,12 @@ impl TraitBounds {
         }
         impl Eq for SpanlessTy<'_, '_> {}
 
-        if gen.span.from_expansion() {
+        if generics.span.from_expansion() {
             return;
         }
         let mut map: UnhashMap<SpanlessTy<'_, '_>, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
-        for bound in gen.predicates {
+        for bound in generics.predicates {
             if let WherePredicate::BoundPredicate(ref p) = bound
                 && p.origin != PredicateOrigin::ImplTrait
                 && p.bounds.len() as u64 <= self.max_trait_bounds
@@ -301,8 +301,8 @@ impl TraitBounds {
     }
 }
 
-fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
-    if gen.span.from_expansion() {
+fn check_trait_bound_duplication(cx: &LateContext<'_>, generics: &'_ Generics<'_>) {
+    if generics.span.from_expansion() {
         return;
     }
 
@@ -313,7 +313,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
     //       |
     // collects each of these where clauses into a set keyed by generic name and comparable trait
     // eg. (T, Clone)
-    let where_predicates = gen
+    let where_predicates = generics
         .predicates
         .iter()
         .filter_map(|pred| {
@@ -342,7 +342,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
     //            |
     // compare trait bounds keyed by generic name and comparable trait to collected where
     // predicates eg. (T, Clone)
-    for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) {
+    for predicate in generics.predicates.iter().filter(|pred| !pred.in_where_clause()) {
         if let WherePredicate::BoundPredicate(bound_predicate) = predicate
             && bound_predicate.origin != PredicateOrigin::ImplTrait
             && !bound_predicate.span.from_expansion()
diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
index 0aa50c99c16..b6e765d7c39 100644
--- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
@@ -57,7 +57,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
                     bound
                         .bound_generic_params
                         .iter()
-                        .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
+                        .any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
                 });
                 if has_lifetime_parameters {
                     // complex trait bounds like A<'a, 'b>
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 877a77fd6d2..1d294c2944b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,6 +1,5 @@
 pub mod almost_standard_lint_formulation;
 pub mod collapsible_calls;
-pub mod compiler_lint_functions;
 pub mod interning_defined_symbol;
 pub mod invalid_paths;
 pub mod lint_without_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
deleted file mode 100644
index 9b6b6871818..00000000000
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::match_type;
-use clippy_utils::{is_lint_allowed, paths};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::impl_lint_pass;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
-    /// variant of the function.
-    ///
-    /// ### Why is this bad?
-    /// The `utils::*` variants also add a link to the Clippy documentation to the
-    /// warning/error messages.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// cx.span_lint(LINT_NAME, "message");
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// utils::span_lint(cx, LINT_NAME, "message");
-    /// ```
-    pub COMPILER_LINT_FUNCTIONS,
-    internal,
-    "usage of the lint functions of the compiler instead of the utils::* variant"
-}
-
-impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
-
-#[derive(Clone, Default)]
-pub struct CompilerLintFunctions {
-    map: FxHashMap<&'static str, &'static str>,
-}
-
-impl CompilerLintFunctions {
-    #[must_use]
-    pub fn new() -> Self {
-        let mut map = FxHashMap::default();
-        map.insert("span_lint", "utils::span_lint");
-        map.insert("lint", "utils::span_lint");
-        map.insert("span_lint_note", "utils::span_lint_and_note");
-        map.insert("span_lint_help", "utils::span_lint_and_help");
-        Self { map }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
-            return;
-        }
-
-        if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind
-            && let fn_name = path.ident
-            && let Some(sugg) = self.map.get(fn_name.as_str())
-            && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
-            && (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT))
-        {
-            span_lint_and_help(
-                cx,
-                COMPILER_LINT_FUNCTIONS,
-                path.ident.span,
-                "usage of a compiler lint function",
-                None,
-                format!("please use the Clippy variant of this function: `{sugg}`"),
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 436f0cb79fb..a0a60ca8875 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_test_module_or_function;
+use clippy_utils::is_in_test;
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -100,7 +100,6 @@ declare_clippy_lint! {
 #[derive(Default)]
 pub struct WildcardImports {
     warn_on_all: bool,
-    test_modules_deep: u32,
     allowed_segments: FxHashSet<String>,
 }
 
@@ -108,7 +107,6 @@ impl WildcardImports {
     pub fn new(warn_on_all: bool, allowed_wildcard_imports: FxHashSet<String>) -> Self {
         Self {
             warn_on_all,
-            test_modules_deep: 0,
             allowed_segments: allowed_wildcard_imports,
         }
     }
@@ -122,15 +120,12 @@ impl LateLintPass<'_> for WildcardImports {
             return;
         }
 
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
-        }
         let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id);
         if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
             return;
         }
         if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind
-            && (self.warn_on_all || !self.check_exceptions(item, use_path.segments))
+            && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments))
             && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id)
             && !used_imports.is_empty() // Already handled by `unused_imports`
             && !used_imports.contains(&kw::Underscore)
@@ -180,20 +175,14 @@ impl LateLintPass<'_> for WildcardImports {
             span_lint_and_sugg(cx, lint, span, message, "try", sugg, applicability);
         }
     }
-
-    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
-        }
-    }
 }
 
 impl WildcardImports {
-    fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
+    fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
         item.span.from_expansion()
             || is_prelude_import(segments)
-            || (is_super_only_import(segments) && self.test_modules_deep > 0)
             || is_allowed_via_config(segments, &self.allowed_segments)
+            || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id()))
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 652ce88bd95..96e53b7ef0b 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall};
 use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_ast::token::LitKind;
 use rustc_ast::{
     FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
@@ -297,8 +297,7 @@ impl<'tcx> LateLintPass<'tcx> for Write {
             .as_ref()
             .map_or(false, |crate_name| crate_name == "build_script_build");
 
-        let allowed_in_tests = self.allow_print_in_tests
-            && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id));
+        let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id);
         match diag_name {
             sym::print_macro | sym::println_macro if !allowed_in_tests => {
                 if !is_build_script {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 935a25d7931..bdb3b5e45c4 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -102,10 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr,
-    ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
-    ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment,
-    PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
+    self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext,
+    Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
+    ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
+    PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
+    TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -210,7 +211,10 @@ pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {
     false
 }
 
-/// Returns `true` if the given `NodeId` is inside a constant context
+/// Returns `true` if the given `HirId` is inside a constant context.
+///
+/// This is the same as `is_inside_always_const_context`, but also includes
+/// `const fn`.
 ///
 /// # Example
 ///
@@ -223,6 +227,24 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
     cx.tcx.hir().is_inside_const_context(id)
 }
 
+/// Returns `true` if the given `HirId` is inside an always constant context.
+///
+/// This context includes:
+///  * const/static items
+///  * const blocks (or inline consts)
+///  * associated constants
+pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
+    use ConstContext::{Const, ConstFn, Static};
+    let hir = tcx.hir();
+    let Some(ctx) = hir.body_const_context(hir.enclosing_body_owner(hir_id)) else {
+        return false;
+    };
+    match ctx {
+        ConstFn => false,
+        Static(_) | Const { inline: _ } => true,
+    }
+}
+
 /// Checks if a `Res` refers to a constructor of a `LangItem`
 /// For example, use this to check whether a function call or a pattern is `Some(..)`.
 pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool {
@@ -1904,8 +1926,18 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool
     false
 }
 
-pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
-    any_parent_has_attr(tcx, node, sym::automatically_derived)
+/// Checks if the given HIR node is inside an `impl` block with the `automatically_derived`
+/// attribute.
+pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
+    tcx.hir()
+        .parent_owner_iter(id)
+        .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_))))
+        .any(|(id, _)| {
+            has_attr(
+                tcx.hir().attrs(tcx.local_def_id_to_hir_id(id.def_id)),
+                sym::automatically_derived,
+            )
+        })
 }
 
 /// Matches a function call with the given path and returns the arguments.
@@ -2472,6 +2504,17 @@ pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)
     }
 }
 
+/// Peels off all references on the type. Returns the underlying type and the number of references
+/// removed.
+pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
+    let mut count = 0;
+    while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
+        ty = *dest_ty;
+        count += 1;
+    }
+    (ty, count)
+}
+
 /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
 /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
 pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
@@ -2594,16 +2637,6 @@ pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
             .any(|attr| attr.has_name(sym::cfg))
 }
 
-/// Checks whether item either has `test` attribute applied, or
-/// is a module with `test` in its name.
-///
-/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
-pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
-    is_in_test_function(tcx, item.hir_id())
-        || matches!(item.kind, ItemKind::Mod(..))
-            && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
-}
-
 /// Walks up the HIR tree from the given expression in an attempt to find where the value is
 /// consumed.
 ///
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 3f66813801d..d5a3d8b9e5a 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -88,6 +88,7 @@ pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"
 pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
 pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
 pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
+pub const STRING_FROM_UTF8: [&str; 4] = ["alloc", "string", "String", "from_utf8"];
 #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"];
 #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index acaeb93f44a..fc02b974ee1 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -96,11 +96,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         return false;
                     }
 
-                    for (predicate, _span) in cx
-                        .tcx
-                        .explicit_item_super_predicates(def_id)
-                        .iter_identity_copied()
-                    {
+                    for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).iter_identity_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substitutions to find `U`.
@@ -1332,19 +1328,13 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl
 /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
 pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
     if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) {
-        cx.tcx
-            .inherent_impls(ty_did)
-            .into_iter()
-            .flatten()
-            .map(|&did| {
-                cx.tcx
-                    .associated_items(did)
-                    .filter_by_name_unhygienic(method_name)
-                    .next()
-                    .filter(|item| item.kind == AssocKind::Fn)
-            })
-            .next()
-            .flatten()
+        cx.tcx.inherent_impls(ty_did).into_iter().flatten().find_map(|&did| {
+            cx.tcx
+                .associated_items(did)
+                .filter_by_name_unhygienic(method_name)
+                .next()
+                .filter(|item| item.kind == AssocKind::Fn)
+        })
     } else {
         None
     }
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index ae9e77b8eed..3c86dfe324f 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -16,6 +16,7 @@ clap = { version = "4.4", features = ["derive", "env"] }
 crossbeam-channel = "0.5.6"
 diff = "0.1.13"
 flate2 = "1.0"
+itertools = "0.12"
 rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0.85"
diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md
index 2d6039caeef..47a96e0a03c 100644
--- a/src/tools/clippy/lintcheck/README.md
+++ b/src/tools/clippy/lintcheck/README.md
@@ -7,13 +7,13 @@ repo.  We can then check the diff and spot new or disappearing warnings.
 From the repo root, run:
 
 ```
-cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml
+cargo lintcheck
 ```
 
 or
 
 ```
-cargo lintcheck
+cargo run --target-dir lintcheck/target --manifest-path lintcheck/Cargo.toml
 ```
 
 By default, the logs will be saved into
@@ -33,6 +33,8 @@ the 200 recently most downloaded crates:
 cargo lintcheck popular -n 200 custom.toml
 ```
 
+> Note: Lintcheck isn't sandboxed. Only use it to check crates that you trust or
+> sandbox it manually.
 
 ### Configuring the Crate Sources
 
@@ -65,17 +67,11 @@ sources.
 #### Command Line Options (optional)
 
 ```toml
-bitflags = {name = "bitflags", versions = ['1.2.1'], options = ['-Wclippy::pedantic', '-Wclippy::cargo']}
+clap = {name = "clap", versions = ['4.5.8'], options = ['-Fderive']}
 ```
 
 It is possible to specify command line options for each crate. This makes it
-possible to only check a crate for certain lint groups. If no options are
-specified, the lint groups `clippy::all`, `clippy::pedantic`, and
-`clippy::cargo` are checked. If an empty array is specified only `clippy::all`
-is checked.
-
-**Note:** `-Wclippy::all` is always enabled by default, unless `-Aclippy::all`
-is explicitly specified in the options.
+possible to enable or disable features.
 
 ### Fix mode
 You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and
diff --git a/src/tools/clippy/lintcheck/lintcheck_crates.toml b/src/tools/clippy/lintcheck/lintcheck_crates.toml
index 52f7fee47b6..ff608e6f935 100644
--- a/src/tools/clippy/lintcheck/lintcheck_crates.toml
+++ b/src/tools/clippy/lintcheck/lintcheck_crates.toml
@@ -1,38 +1,38 @@
 [crates]
 # some of these are from cargotest
-cargo = {name = "cargo", versions = ['0.64.0']}
-iron = {name = "iron", versions = ['0.6.1']}
-ripgrep = {name = "ripgrep", versions = ['12.1.1']}
-xsv = {name = "xsv", versions = ['0.13.0']}
+cargo = {name = "cargo", version = '0.64.0'}
+iron = {name = "iron", version = '0.6.1'}
+ripgrep = {name = "ripgrep", version = '12.1.1'}
+xsv = {name = "xsv", version = '0.13.0'}
 # commented out because of 173K clippy::match_same_arms msgs in language_type.rs
-#tokei = { name = "tokei", versions = ['12.0.4']}
-rayon = {name = "rayon", versions = ['1.5.0']}
-serde = {name = "serde", versions = ['1.0.118']}
+#tokei = { name = "tokei", version = '12.0.4'}
+rayon = {name = "rayon", version = '1.5.0'}
+serde = {name = "serde", version = '1.0.118'}
 # top 10 crates.io dls
-bitflags = {name = "bitflags", versions = ['1.2.1']}
+bitflags = {name = "bitflags", version = '1.2.1'}
 # crash = {name = "clippy_crash", path = "/tmp/clippy_crash"}
-libc = {name = "libc", versions = ['0.2.81']}
-log = {name = "log", versions = ['0.4.11']}
-proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']}
-quote = {name = "quote", versions = ['1.0.7']}
-rand = {name = "rand", versions = ['0.7.3']}
-rand_core = {name = "rand_core", versions = ['0.6.0']}
-regex = {name = "regex", versions = ['1.3.2']}
-syn = {name = "syn", versions = ['1.0.54']}
-unicode-xid = {name = "unicode-xid", versions = ['0.2.1']}
+libc = {name = "libc", version = '0.2.81'}
+log = {name = "log", version = '0.4.11'}
+proc-macro2 = {name = "proc-macro2", version = '1.0.24'}
+quote = {name = "quote", version = '1.0.7'}
+rand = {name = "rand", version = '0.7.3'}
+rand_core = {name = "rand_core", version = '0.6.0'}
+regex = {name = "regex", version = '1.3.2'}
+syn = {name = "syn", version = '1.0.54'}
+unicode-xid = {name = "unicode-xid", version = '0.2.1'}
 # some more of dtolnays crates
-anyhow = {name = "anyhow", versions = ['1.0.38']}
-async-trait = {name = "async-trait", versions = ['0.1.42']}
-cxx = {name = "cxx", versions = ['1.0.32']}
-ryu = {name = "ryu", versions = ['1.0.5']}
-serde_yaml = {name = "serde_yaml", versions = ['0.8.17']}
-thiserror = {name = "thiserror", versions = ['1.0.24']}
+anyhow = {name = "anyhow", version = '1.0.38'}
+async-trait = {name = "async-trait", version = '0.1.42'}
+cxx = {name = "cxx", version = '1.0.32'}
+ryu = {name = "ryu", version = '1.0.5'}
+serde_yaml = {name = "serde_yaml", version = '0.8.17'}
+thiserror = {name = "thiserror", version = '1.0.24'}
 # some embark crates, there are other interesting crates but
 # unfortunately adding them increases lintcheck runtime drastically
-cfg-expr = {name = "cfg-expr", versions = ['0.7.1']}
+cfg-expr = {name = "cfg-expr", version = '0.7.1'}
 puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"}
-rpmalloc = {name = "rpmalloc", versions = ['0.2.0']}
-tame-oidc = {name = "tame-oidc", versions = ['0.1.0']}
+rpmalloc = {name = "rpmalloc", version = '0.2.0'}
+tame-oidc = {name = "tame-oidc", version = '0.1.0'}
 
 [recursive]
 ignore = [
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index e6cd7c9fdc2..b35a62eed44 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -36,6 +36,10 @@ pub(crate) struct LintcheckConfig {
     /// Apply a filter to only collect specified lints, this also overrides `allow` attributes
     #[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
+    #[clap(long, conflicts_with("lint_filter"))]
+    pub warn_all: 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/driver.rs b/src/tools/clippy/lintcheck/src/driver.rs
index 47724a2fedb..041be5081f2 100644
--- a/src/tools/clippy/lintcheck/src/driver.rs
+++ b/src/tools/clippy/lintcheck/src/driver.rs
@@ -11,8 +11,6 @@ use std::{env, mem};
 fn run_clippy(addr: &str) -> Option<i32> {
     let driver_info = DriverInfo {
         package_name: env::var("CARGO_PKG_NAME").ok()?,
-        crate_name: env::var("CARGO_CRATE_NAME").ok()?,
-        version: env::var("CARGO_PKG_VERSION").ok()?,
     };
 
     let mut stream = BufReader::new(TcpStream::connect(addr).unwrap());
diff --git a/src/tools/clippy/lintcheck/src/input.rs b/src/tools/clippy/lintcheck/src/input.rs
new file mode 100644
index 00000000000..3d034391c28
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/input.rs
@@ -0,0 +1,288 @@
+use std::collections::{HashMap, HashSet};
+use std::fs::{self};
+use std::io::{self, ErrorKind};
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use std::time::Duration;
+
+use serde::Deserialize;
+use walkdir::{DirEntry, WalkDir};
+
+use crate::{Crate, LINTCHECK_DOWNLOADS, LINTCHECK_SOURCES};
+
+/// List of sources to check, loaded from a .toml file
+#[derive(Debug, Deserialize)]
+pub struct SourceList {
+    crates: HashMap<String, TomlCrate>,
+    #[serde(default)]
+    recursive: RecursiveOptions,
+}
+
+#[derive(Debug, Deserialize, Default)]
+pub struct RecursiveOptions {
+    pub ignore: HashSet<String>,
+}
+
+/// A crate source stored inside the .toml
+/// will be translated into on one of the `CrateSource` variants
+#[derive(Debug, Deserialize)]
+struct TomlCrate {
+    name: String,
+    version: Option<String>,
+    git_url: Option<String>,
+    git_hash: Option<String>,
+    path: Option<String>,
+    options: Option<Vec<String>>,
+}
+
+/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder
+/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate`
+#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)]
+pub enum CrateSource {
+    CratesIo {
+        name: String,
+        version: String,
+        options: Option<Vec<String>>,
+    },
+    Git {
+        name: String,
+        url: String,
+        commit: String,
+        options: Option<Vec<String>>,
+    },
+    Path {
+        name: String,
+        path: PathBuf,
+        options: Option<Vec<String>>,
+    },
+}
+
+/// Read a `lintcheck_crates.toml` file
+pub fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
+    let toml_content: String =
+        fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
+    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();
+
+    // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
+    // multiple Cratesources)
+    let mut crate_sources = Vec::new();
+    for tk in tomlcrates {
+        if let Some(ref path) = tk.path {
+            crate_sources.push(CrateSource::Path {
+                name: tk.name.clone(),
+                path: PathBuf::from(path),
+                options: tk.options.clone(),
+            });
+        } else if let Some(ref version) = tk.version {
+            crate_sources.push(CrateSource::CratesIo {
+                name: tk.name.clone(),
+                version: version.to_string(),
+                options: tk.options.clone(),
+            });
+        } else if tk.git_url.is_some() && tk.git_hash.is_some() {
+            // otherwise, we should have a git source
+            crate_sources.push(CrateSource::Git {
+                name: tk.name.clone(),
+                url: tk.git_url.clone().unwrap(),
+                commit: tk.git_hash.clone().unwrap(),
+                options: tk.options.clone(),
+            });
+        } else {
+            panic!("Invalid crate source: {tk:?}");
+        }
+
+        // if we have a version as well as a git data OR only one git data, something is funky
+        if tk.version.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some())
+            || tk.git_hash.is_some() != tk.git_url.is_some()
+        {
+            eprintln!("tomlkrate: {tk:?}");
+            assert_eq!(
+                tk.git_hash.is_some(),
+                tk.git_url.is_some(),
+                "Error: Encountered TomlCrate with only one of git_hash and git_url!"
+            );
+            assert!(
+                tk.path.is_none() || (tk.git_hash.is_none() && tk.version.is_none()),
+                "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields"
+            );
+            unreachable!("Failed to translate TomlCrate into CrateSource!");
+        }
+    }
+    // sort the crates
+    crate_sources.sort();
+
+    (crate_sources, crate_list.recursive)
+}
+
+impl CrateSource {
+    /// Makes the sources available on the disk for clippy to check.
+    /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or
+    /// copies a local folder
+    #[expect(clippy::too_many_lines)]
+    pub fn download_and_extract(&self) -> Crate {
+        #[allow(clippy::result_large_err)]
+        fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
+            const MAX_RETRIES: u8 = 4;
+            let mut retries = 0;
+            loop {
+                match ureq::get(path).call() {
+                    Ok(res) => return Ok(res),
+                    Err(e) if retries >= MAX_RETRIES => return Err(e),
+                    Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"),
+                    Err(e) => return Err(e),
+                }
+                eprintln!("retrying in {retries} seconds...");
+                std::thread::sleep(Duration::from_secs(u64::from(retries)));
+                retries += 1;
+            }
+        }
+        match self {
+            CrateSource::CratesIo { name, version, options } => {
+                let extract_dir = PathBuf::from(LINTCHECK_SOURCES);
+                let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS);
+
+                // url to download the crate from crates.io
+                let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download");
+                println!("Downloading and extracting {name} {version} from {url}");
+                create_dirs(&krate_download_dir, &extract_dir);
+
+                let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz"));
+                // don't download/extract if we already have done so
+                if !krate_file_path.is_file() {
+                    // create a file path to download and write the crate data into
+                    let mut krate_dest = fs::File::create(&krate_file_path).unwrap();
+                    let mut krate_req = get(&url).unwrap().into_reader();
+                    // copy the crate into the file
+                    io::copy(&mut krate_req, &mut krate_dest).unwrap();
+
+                    // unzip the tarball
+                    let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap());
+                    // extract the tar archive
+                    let mut archive = tar::Archive::new(ungz_tar);
+                    archive.unpack(&extract_dir).expect("Failed to extract!");
+                }
+                // crate is extracted, return a new Krate object which contains the path to the extracted
+                // sources that clippy can check
+                Crate {
+                    version: version.clone(),
+                    name: name.clone(),
+                    path: extract_dir.join(format!("{name}-{version}/")),
+                    options: options.clone(),
+                }
+            },
+            CrateSource::Git {
+                name,
+                url,
+                commit,
+                options,
+            } => {
+                let repo_path = {
+                    let mut repo_path = PathBuf::from(LINTCHECK_SOURCES);
+                    // add a -git suffix in case we have the same crate from crates.io and a git repo
+                    repo_path.push(format!("{name}-git"));
+                    repo_path
+                };
+                // clone the repo if we have not done so
+                if !repo_path.is_dir() {
+                    println!("Cloning {url} and checking out {commit}");
+                    if !Command::new("git")
+                        .arg("clone")
+                        .arg(url)
+                        .arg(&repo_path)
+                        .status()
+                        .expect("Failed to clone git repo!")
+                        .success()
+                    {
+                        eprintln!("Failed to clone {url} into {}", repo_path.display());
+                    }
+                }
+                // check out the commit/branch/whatever
+                if !Command::new("git")
+                    .args(["-c", "advice.detachedHead=false"])
+                    .arg("checkout")
+                    .arg(commit)
+                    .current_dir(&repo_path)
+                    .status()
+                    .expect("Failed to check out commit")
+                    .success()
+                {
+                    eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display());
+                }
+
+                Crate {
+                    version: commit.clone(),
+                    name: name.clone(),
+                    path: repo_path,
+                    options: options.clone(),
+                }
+            },
+            CrateSource::Path { name, path, options } => {
+                fn is_cache_dir(entry: &DirEntry) -> bool {
+                    fs::read(entry.path().join("CACHEDIR.TAG"))
+                        .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
+                        .unwrap_or(false)
+                }
+
+                // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file.
+                // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory
+                // as a result of this filter.
+                let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name);
+                if dest_crate_root.exists() {
+                    println!("Deleting existing directory at {dest_crate_root:?}");
+                    fs::remove_dir_all(&dest_crate_root).unwrap();
+                }
+
+                println!("Copying {path:?} to {dest_crate_root:?}");
+
+                for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) {
+                    let entry = entry.unwrap();
+                    let entry_path = entry.path();
+                    let relative_entry_path = entry_path.strip_prefix(path).unwrap();
+                    let dest_path = dest_crate_root.join(relative_entry_path);
+                    let metadata = entry_path.symlink_metadata().unwrap();
+
+                    if metadata.is_dir() {
+                        fs::create_dir(dest_path).unwrap();
+                    } else if metadata.is_file() {
+                        fs::copy(entry_path, dest_path).unwrap();
+                    }
+                }
+
+                Crate {
+                    version: String::from("local"),
+                    name: name.clone(),
+                    path: dest_crate_root,
+                    options: options.clone(),
+                }
+            },
+        }
+    }
+}
+
+/// Create necessary directories to run the lintcheck tool.
+///
+/// # Panics
+///
+/// This function panics if creating one of the dirs fails.
+fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
+    fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
+        assert_eq!(
+            err.kind(),
+            ErrorKind::AlreadyExists,
+            "cannot create lintcheck target dir"
+        );
+    });
+    fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
+        assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir");
+    });
+    fs::create_dir(extract_dir).unwrap_or_else(|err| {
+        assert_eq!(
+            err.kind(),
+            ErrorKind::AlreadyExists,
+            "cannot create crate extraction dir"
+        );
+    });
+}
diff --git a/src/tools/clippy/lintcheck/src/json.rs b/src/tools/clippy/lintcheck/src/json.rs
index 43d0413c7ce..1a652927988 100644
--- a/src/tools/clippy/lintcheck/src/json.rs
+++ b/src/tools/clippy/lintcheck/src/json.rs
@@ -1,37 +1,50 @@
-use std::collections::HashMap;
-use std::fmt::Write;
 use std::fs;
-use std::hash::Hash;
 use std::path::Path;
 
+use itertools::EitherOrBoth;
+use serde::{Deserialize, Serialize};
+
 use crate::ClippyWarning;
 
-/// Creates the log file output for [`crate::config::OutputFormat::Json`]
-pub(crate) fn output(clippy_warnings: &[ClippyWarning]) -> String {
-    serde_json::to_string(&clippy_warnings).unwrap()
+#[derive(Deserialize, Serialize)]
+struct LintJson {
+    lint: String,
+    file_name: String,
+    byte_pos: (u32, u32),
+    rendered: String,
 }
 
-fn load_warnings(path: &Path) -> Vec<ClippyWarning> {
-    let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
-
-    serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display()))
+impl LintJson {
+    fn key(&self) -> impl Ord + '_ {
+        (self.file_name.as_str(), self.byte_pos, self.lint.as_str())
+    }
 }
 
-/// Group warnings by their primary span location + lint name
-fn create_map(warnings: &[ClippyWarning]) -> HashMap<impl Eq + Hash + '_, Vec<&ClippyWarning>> {
-    let mut map = HashMap::<_, Vec<_>>::with_capacity(warnings.len());
-
-    for warning in warnings {
-        let span = warning.span();
-        let key = (&warning.lint_type, &span.file_name, span.byte_start, span.byte_end);
+/// Creates the log file output for [`crate::config::OutputFormat::Json`]
+pub(crate) fn output(clippy_warnings: Vec<ClippyWarning>) -> String {
+    let mut lints: Vec<LintJson> = clippy_warnings
+        .into_iter()
+        .map(|warning| {
+            let span = warning.span();
+            LintJson {
+                file_name: span.file_name.clone(),
+                byte_pos: (span.byte_start, span.byte_end),
+                lint: warning.lint,
+                rendered: warning.diag.rendered.unwrap(),
+            }
+        })
+        .collect();
+    lints.sort_by(|a, b| a.key().cmp(&b.key()));
+    serde_json::to_string(&lints).unwrap()
+}
 
-        map.entry(key).or_default().push(warning);
-    }
+fn load_warnings(path: &Path) -> Vec<LintJson> {
+    let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
 
-    map
+    serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display()))
 }
 
-fn print_warnings(title: &str, warnings: &[&ClippyWarning]) {
+fn print_warnings(title: &str, warnings: &[LintJson]) {
     if warnings.is_empty() {
         return;
     }
@@ -39,31 +52,20 @@ fn print_warnings(title: &str, warnings: &[&ClippyWarning]) {
     println!("### {title}");
     println!("```");
     for warning in warnings {
-        print!("{}", warning.diag);
+        print!("{}", warning.rendered);
     }
     println!("```");
 }
 
-fn print_changed_diff(changed: &[(&[&ClippyWarning], &[&ClippyWarning])]) {
-    fn render(warnings: &[&ClippyWarning]) -> String {
-        let mut rendered = String::new();
-        for warning in warnings {
-            write!(&mut rendered, "{}", warning.diag).unwrap();
-        }
-        rendered
-    }
-
+fn print_changed_diff(changed: &[(LintJson, LintJson)]) {
     if changed.is_empty() {
         return;
     }
 
     println!("### Changed");
     println!("```diff");
-    for &(old, new) in changed {
-        let old_rendered = render(old);
-        let new_rendered = render(new);
-
-        for change in diff::lines(&old_rendered, &new_rendered) {
+    for (old, new) in changed {
+        for change in diff::lines(&old.rendered, &new.rendered) {
             use diff::Result::{Both, Left, Right};
 
             match change {
@@ -86,26 +88,19 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path) {
     let old_warnings = load_warnings(old_path);
     let new_warnings = load_warnings(new_path);
 
-    let old_map = create_map(&old_warnings);
-    let new_map = create_map(&new_warnings);
-
     let mut added = Vec::new();
     let mut removed = Vec::new();
     let mut changed = Vec::new();
 
-    for (key, new) in &new_map {
-        if let Some(old) = old_map.get(key) {
-            if old != new {
-                changed.push((old.as_slice(), new.as_slice()));
-            }
-        } else {
-            added.extend(new);
-        }
-    }
-
-    for (key, old) in &old_map {
-        if !new_map.contains_key(key) {
-            removed.extend(old);
+    for change in itertools::merge_join_by(old_warnings, new_warnings, |old, new| old.key().cmp(&new.key())) {
+        match change {
+            EitherOrBoth::Both(old, new) => {
+                if old.rendered != new.rendered {
+                    changed.push((old, new));
+                }
+            },
+            EitherOrBoth::Left(old) => removed.push(old),
+            EitherOrBoth::Right(new) => added.push(new),
         }
     }
 
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index ec72e0eb5dc..e37ffab13ac 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -5,6 +5,7 @@
 // When a new lint is introduced, we can search the results for new warnings and check for false
 // positives.
 
+#![feature(iter_collect_into)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
@@ -12,84 +13,38 @@
     unused_lifetimes,
     unused_qualifications
 )]
-#![allow(clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args)]
+#![allow(
+    clippy::collapsible_else_if,
+    clippy::needless_borrows_for_generic_args,
+    clippy::module_name_repetitions
+)]
 
 mod config;
 mod driver;
+mod input;
 mod json;
+mod output;
 mod popular_crates;
 mod recursive;
 
 use crate::config::{Commands, LintcheckConfig, OutputFormat};
 use crate::recursive::LintcheckServer;
 
-use std::collections::{HashMap, HashSet};
 use std::env::consts::EXE_SUFFIX;
-use std::fmt::{self, Display, Write as _};
-use std::hash::Hash;
-use std::io::{self, ErrorKind};
+use std::io::{self};
 use std::path::{Path, PathBuf};
-use std::process::{Command, ExitStatus, Stdio};
+use std::process::{Command, Stdio};
 use std::sync::atomic::{AtomicUsize, Ordering};
-use std::time::Duration;
-use std::{env, fs, thread};
+use std::{env, fs};
 
-use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan};
 use cargo_metadata::Message;
+use input::{read_crates, CrateSource};
+use output::{ClippyCheckOutput, ClippyWarning, RustcIce};
 use rayon::prelude::*;
-use serde::{Deserialize, Serialize};
-use walkdir::{DirEntry, WalkDir};
 
 const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads";
 const LINTCHECK_SOURCES: &str = "target/lintcheck/sources";
 
-/// List of sources to check, loaded from a .toml file
-#[derive(Debug, Deserialize)]
-struct SourceList {
-    crates: HashMap<String, TomlCrate>,
-    #[serde(default)]
-    recursive: RecursiveOptions,
-}
-
-#[derive(Debug, Deserialize, Default)]
-struct RecursiveOptions {
-    ignore: HashSet<String>,
-}
-
-/// A crate source stored inside the .toml
-/// will be translated into on one of the `CrateSource` variants
-#[derive(Debug, Deserialize)]
-struct TomlCrate {
-    name: String,
-    versions: Option<Vec<String>>,
-    git_url: Option<String>,
-    git_hash: Option<String>,
-    path: Option<String>,
-    options: Option<Vec<String>>,
-}
-
-/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder
-/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate`
-#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)]
-enum CrateSource {
-    CratesIo {
-        name: String,
-        version: String,
-        options: Option<Vec<String>>,
-    },
-    Git {
-        name: String,
-        url: String,
-        commit: String,
-        options: Option<Vec<String>>,
-    },
-    Path {
-        name: String,
-        path: PathBuf,
-        options: Option<Vec<String>>,
-    },
-}
-
 /// Represents the actual source code of a crate that we ran "cargo clippy" on
 #[derive(Debug)]
 struct Crate {
@@ -100,248 +55,6 @@ struct Crate {
     options: Option<Vec<String>>,
 }
 
-/// A single emitted output from clippy being executed on a crate. It may either be a
-/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many
-/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution).
-#[derive(Debug)]
-enum ClippyCheckOutput {
-    ClippyWarning(ClippyWarning),
-    RustcIce(RustcIce),
-}
-
-#[derive(Debug)]
-struct RustcIce {
-    pub crate_name: String,
-    pub ice_content: String,
-}
-
-impl Display for RustcIce {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{}:\n{}\n========================================\n",
-            self.crate_name, self.ice_content
-        )
-    }
-}
-
-impl RustcIce {
-    pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option<Self> {
-        if status.code().unwrap_or(0) == 101
-        /* ice exit status */
-        {
-            Some(Self {
-                crate_name: crate_name.to_owned(),
-                ice_content: stderr.to_owned(),
-            })
-        } else {
-            None
-        }
-    }
-}
-
-/// A single warning that clippy issued while checking a `Crate`
-#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
-struct ClippyWarning {
-    crate_name: String,
-    crate_version: String,
-    lint_type: String,
-    diag: Diagnostic,
-}
-
-#[allow(unused)]
-impl ClippyWarning {
-    fn new(mut diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option<Self> {
-        let lint_type = diag.code.clone()?.code;
-        if !(lint_type.contains("clippy") || diag.message.contains("clippy"))
-            || diag.message.contains("could not read cargo metadata")
-        {
-            return None;
-        }
-
-        // --recursive bypasses cargo so we have to strip the rendered output ourselves
-        let rendered = diag.rendered.as_mut().unwrap();
-        *rendered = strip_ansi_escapes::strip_str(&rendered);
-
-        Some(Self {
-            crate_name: crate_name.to_owned(),
-            crate_version: crate_version.to_owned(),
-            lint_type,
-            diag,
-        })
-    }
-
-    fn span(&self) -> &DiagnosticSpan {
-        self.diag.spans.iter().find(|span| span.is_primary).unwrap()
-    }
-
-    fn to_output(&self, format: OutputFormat) -> String {
-        let span = self.span();
-        let mut file = span.file_name.clone();
-        let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end);
-        match format {
-            OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.diag.message),
-            OutputFormat::Markdown => {
-                if file.starts_with("target") {
-                    file.insert_str(0, "../");
-                }
-
-                let mut output = String::from("| ");
-                write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap();
-                write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.diag.message).unwrap();
-                output.push('\n');
-                output
-            },
-            OutputFormat::Json => unreachable!("JSON output is handled via serde"),
-        }
-    }
-}
-
-#[allow(clippy::result_large_err)]
-fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
-    const MAX_RETRIES: u8 = 4;
-    let mut retries = 0;
-    loop {
-        match ureq::get(path).call() {
-            Ok(res) => return Ok(res),
-            Err(e) if retries >= MAX_RETRIES => return Err(e),
-            Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"),
-            Err(e) => return Err(e),
-        }
-        eprintln!("retrying in {retries} seconds...");
-        thread::sleep(Duration::from_secs(u64::from(retries)));
-        retries += 1;
-    }
-}
-
-impl CrateSource {
-    /// Makes the sources available on the disk for clippy to check.
-    /// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or
-    /// copies a local folder
-    fn download_and_extract(&self) -> Crate {
-        match self {
-            CrateSource::CratesIo { name, version, options } => {
-                let extract_dir = PathBuf::from(LINTCHECK_SOURCES);
-                let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS);
-
-                // url to download the crate from crates.io
-                let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download");
-                println!("Downloading and extracting {name} {version} from {url}");
-                create_dirs(&krate_download_dir, &extract_dir);
-
-                let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz"));
-                // don't download/extract if we already have done so
-                if !krate_file_path.is_file() {
-                    // create a file path to download and write the crate data into
-                    let mut krate_dest = fs::File::create(&krate_file_path).unwrap();
-                    let mut krate_req = get(&url).unwrap().into_reader();
-                    // copy the crate into the file
-                    io::copy(&mut krate_req, &mut krate_dest).unwrap();
-
-                    // unzip the tarball
-                    let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap());
-                    // extract the tar archive
-                    let mut archive = tar::Archive::new(ungz_tar);
-                    archive.unpack(&extract_dir).expect("Failed to extract!");
-                }
-                // crate is extracted, return a new Krate object which contains the path to the extracted
-                // sources that clippy can check
-                Crate {
-                    version: version.clone(),
-                    name: name.clone(),
-                    path: extract_dir.join(format!("{name}-{version}/")),
-                    options: options.clone(),
-                }
-            },
-            CrateSource::Git {
-                name,
-                url,
-                commit,
-                options,
-            } => {
-                let repo_path = {
-                    let mut repo_path = PathBuf::from(LINTCHECK_SOURCES);
-                    // add a -git suffix in case we have the same crate from crates.io and a git repo
-                    repo_path.push(format!("{name}-git"));
-                    repo_path
-                };
-                // clone the repo if we have not done so
-                if !repo_path.is_dir() {
-                    println!("Cloning {url} and checking out {commit}");
-                    if !Command::new("git")
-                        .arg("clone")
-                        .arg(url)
-                        .arg(&repo_path)
-                        .status()
-                        .expect("Failed to clone git repo!")
-                        .success()
-                    {
-                        eprintln!("Failed to clone {url} into {}", repo_path.display());
-                    }
-                }
-                // check out the commit/branch/whatever
-                if !Command::new("git")
-                    .args(["-c", "advice.detachedHead=false"])
-                    .arg("checkout")
-                    .arg(commit)
-                    .current_dir(&repo_path)
-                    .status()
-                    .expect("Failed to check out commit")
-                    .success()
-                {
-                    eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display());
-                }
-
-                Crate {
-                    version: commit.clone(),
-                    name: name.clone(),
-                    path: repo_path,
-                    options: options.clone(),
-                }
-            },
-            CrateSource::Path { name, path, options } => {
-                fn is_cache_dir(entry: &DirEntry) -> bool {
-                    fs::read(entry.path().join("CACHEDIR.TAG"))
-                        .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
-                        .unwrap_or(false)
-                }
-
-                // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file.
-                // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory
-                // as a result of this filter.
-                let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name);
-                if dest_crate_root.exists() {
-                    println!("Deleting existing directory at {dest_crate_root:?}");
-                    fs::remove_dir_all(&dest_crate_root).unwrap();
-                }
-
-                println!("Copying {path:?} to {dest_crate_root:?}");
-
-                for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) {
-                    let entry = entry.unwrap();
-                    let entry_path = entry.path();
-                    let relative_entry_path = entry_path.strip_prefix(path).unwrap();
-                    let dest_path = dest_crate_root.join(relative_entry_path);
-                    let metadata = entry_path.symlink_metadata().unwrap();
-
-                    if metadata.is_dir() {
-                        fs::create_dir(dest_path).unwrap();
-                    } else if metadata.is_file() {
-                        fs::copy(entry_path, dest_path).unwrap();
-                    }
-                }
-
-                Crate {
-                    version: String::from("local"),
-                    name: name.clone(),
-                    path: dest_crate_root,
-                    options: options.clone(),
-                }
-            },
-        }
-    }
-}
-
 impl Crate {
     /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy
     /// issued
@@ -352,7 +65,7 @@ impl Crate {
         target_dir_index: &AtomicUsize,
         total_crates_to_lint: usize,
         config: &LintcheckConfig,
-        lint_filter: &[String],
+        lint_levels_args: &[String],
         server: &Option<LintcheckServer>,
     ) -> Vec<ClippyCheckOutput> {
         // advance the atomic index by one
@@ -398,16 +111,9 @@ impl Crate {
             for opt in options {
                 clippy_args.push(opt);
             }
-        } else {
-            clippy_args.extend(["-Wclippy::pedantic", "-Wclippy::cargo"]);
         }
 
-        if lint_filter.is_empty() {
-            clippy_args.push("--cap-lints=warn");
-        } else {
-            clippy_args.push("--cap-lints=allow");
-            clippy_args.extend(lint_filter.iter().map(String::as_str));
-        }
+        clippy_args.extend(lint_levels_args.iter().map(String::as_str));
 
         let mut cmd = Command::new("cargo");
         cmd.arg(if config.fix { "fix" } else { "check" })
@@ -479,7 +185,7 @@ impl Crate {
         // get all clippy warnings and ICEs
         let mut entries: Vec<ClippyCheckOutput> = Message::parse_stream(stdout.as_bytes())
             .filter_map(|msg| match msg {
-                Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version),
+                Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message),
                 _ => None,
             })
             .map(ClippyCheckOutput::ClippyWarning)
@@ -509,96 +215,6 @@ fn build_clippy() -> String {
     String::from_utf8_lossy(&output.stdout).into_owned()
 }
 
-/// Read a `lintcheck_crates.toml` file
-fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
-    let toml_content: String =
-        fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
-    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();
-
-    // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
-    // multiple Cratesources)
-    let mut crate_sources = Vec::new();
-    for tk in tomlcrates {
-        if let Some(ref path) = tk.path {
-            crate_sources.push(CrateSource::Path {
-                name: tk.name.clone(),
-                path: PathBuf::from(path),
-                options: tk.options.clone(),
-            });
-        } else if let Some(ref versions) = tk.versions {
-            // if we have multiple versions, save each one
-            for ver in versions {
-                crate_sources.push(CrateSource::CratesIo {
-                    name: tk.name.clone(),
-                    version: ver.to_string(),
-                    options: tk.options.clone(),
-                });
-            }
-        } else if tk.git_url.is_some() && tk.git_hash.is_some() {
-            // otherwise, we should have a git source
-            crate_sources.push(CrateSource::Git {
-                name: tk.name.clone(),
-                url: tk.git_url.clone().unwrap(),
-                commit: tk.git_hash.clone().unwrap(),
-                options: tk.options.clone(),
-            });
-        } else {
-            panic!("Invalid crate source: {tk:?}");
-        }
-
-        // if we have a version as well as a git data OR only one git data, something is funky
-        if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some())
-            || tk.git_hash.is_some() != tk.git_url.is_some()
-        {
-            eprintln!("tomlkrate: {tk:?}");
-            assert_eq!(
-                tk.git_hash.is_some(),
-                tk.git_url.is_some(),
-                "Error: Encountered TomlCrate with only one of git_hash and git_url!"
-            );
-            assert!(
-                tk.path.is_none() || (tk.git_hash.is_none() && tk.versions.is_none()),
-                "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields"
-            );
-            unreachable!("Failed to translate TomlCrate into CrateSource!");
-        }
-    }
-    // sort the crates
-    crate_sources.sort();
-
-    (crate_sources, crate_list.recursive)
-}
-
-/// Generate a short list of occurring lints-types and their count
-fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
-    // count lint type occurrences
-    let mut counter: HashMap<&String, usize> = HashMap::new();
-    warnings
-        .iter()
-        .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1);
-
-    // collect into a tupled list for sorting
-    let mut stats: Vec<(&&String, &usize)> = counter.iter().collect();
-    // sort by "000{count} {clippy::lintname}"
-    // to not have a lint with 200 and 2 warnings take the same spot
-    stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}"));
-
-    let mut header = String::from("| lint                                               | count |\n");
-    header.push_str("| -------------------------------------------------- | ----- |\n");
-    let stats_string = stats
-        .iter()
-        .map(|(lint, count)| format!("| {lint:<50} |  {count:>4} |\n"))
-        .fold(header, |mut table, line| {
-            table.push_str(&line);
-            table
-        });
-
-    (stats_string, counter)
-}
-
 fn main() {
     // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive`
     if let Ok(addr) = env::var("LINTCHECK_SERVER") {
@@ -638,15 +254,39 @@ fn lintcheck(config: LintcheckConfig) {
     let (crates, recursive_options) = read_crates(&config.sources_toml_path);
 
     let counter = AtomicUsize::new(1);
-    let lint_filter: Vec<String> = config
-        .lint_filter
-        .iter()
-        .map(|filter| {
-            let mut filter = filter.clone();
-            filter.insert_str(0, "--force-warn=");
-            filter
-        })
-        .collect();
+    let mut lint_level_args: Vec<String> = vec![];
+    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 {
+            [
+                "clippy::cargo",
+                "clippy::nursery",
+                "clippy::pedantic",
+                "clippy::restriction",
+            ]
+            .iter()
+            .map(|group| format!("--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()
+            .map(|filter| {
+                let mut filter = filter.clone();
+                filter.insert_str(0, "--force-warn=");
+                filter
+            })
+            .collect_into(&mut lint_level_args);
+    };
 
     let crates: Vec<Crate> = crates
         .into_iter()
@@ -698,7 +338,7 @@ fn lintcheck(config: LintcheckConfig) {
                 &counter,
                 crates.len(),
                 &config,
-                &lint_filter,
+                &lint_level_args,
                 &server,
             )
         })
@@ -727,7 +367,9 @@ fn lintcheck(config: LintcheckConfig) {
     }
 
     let text = match config.format {
-        OutputFormat::Text | OutputFormat::Markdown => output(&warnings, &raw_ices, clippy_ver, &config),
+        OutputFormat::Text | OutputFormat::Markdown => {
+            output::summarize_and_print_changes(&warnings, &raw_ices, clippy_ver, &config)
+        },
         OutputFormat::Json => {
             if !raw_ices.is_empty() {
                 for ice in raw_ices {
@@ -736,7 +378,7 @@ fn lintcheck(config: LintcheckConfig) {
                 panic!("Some crates ICEd");
             }
 
-            json::output(&warnings)
+            json::output(warnings)
         },
     };
 
@@ -745,135 +387,6 @@ fn lintcheck(config: LintcheckConfig) {
     fs::write(&config.lintcheck_results_path, text).unwrap();
 }
 
-/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`]
-fn output(warnings: &[ClippyWarning], ices: &[RustcIce], clippy_ver: String, config: &LintcheckConfig) -> String {
-    // generate some stats
-    let (stats_formatted, new_stats) = gather_stats(warnings);
-    let old_stats = read_stats_from_file(&config.lintcheck_results_path);
-
-    let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.format)).collect();
-    all_msgs.sort();
-    all_msgs.push("\n\n### Stats:\n\n".into());
-    all_msgs.push(stats_formatted);
-
-    let mut text = clippy_ver; // clippy version number on top
-    text.push_str("\n### Reports\n\n");
-    if config.format == OutputFormat::Markdown {
-        text.push_str("| file | lint | message |\n");
-        text.push_str("| --- | --- | --- |\n");
-    }
-    write!(text, "{}", all_msgs.join("")).unwrap();
-    text.push_str("\n\n### ICEs:\n");
-    for ice in ices {
-        writeln!(text, "{ice}").unwrap();
-    }
-
-    print_stats(old_stats, new_stats, &config.lint_filter);
-
-    text
-}
-
-/// read the previous stats from the lintcheck-log file
-fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
-    let file_content: String = match fs::read_to_string(file_path).ok() {
-        Some(content) => content,
-        None => {
-            return HashMap::new();
-        },
-    };
-
-    let lines: Vec<String> = file_content.lines().map(ToString::to_string).collect();
-
-    lines
-        .iter()
-        .skip_while(|line| line.as_str() != "### Stats:")
-        // Skipping the table header and the `Stats:` label
-        .skip(4)
-        .take_while(|line| line.starts_with("| "))
-        .filter_map(|line| {
-            let mut spl = line.split('|');
-            // Skip the first `|` symbol
-            spl.next();
-            if let (Some(lint), Some(count)) = (spl.next(), spl.next()) {
-                Some((lint.trim().to_string(), count.trim().parse::<usize>().unwrap()))
-            } else {
-                None
-            }
-        })
-        .collect::<HashMap<String, usize>>()
-}
-
-/// print how lint counts changed between runs
-fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &[String]) {
-    let same_in_both_hashmaps = old_stats
-        .iter()
-        .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val))
-        .map(|(k, v)| (k.to_string(), *v))
-        .collect::<Vec<(String, usize)>>();
-
-    let mut old_stats_deduped = old_stats;
-    let mut new_stats_deduped = new_stats;
-
-    // remove duplicates from both hashmaps
-    for (k, v) in &same_in_both_hashmaps {
-        assert!(old_stats_deduped.remove(k) == Some(*v));
-        assert!(new_stats_deduped.remove(k) == Some(*v));
-    }
-
-    println!("\nStats:");
-
-    // list all new counts  (key is in new stats but not in old stats)
-    new_stats_deduped
-        .iter()
-        .filter(|(new_key, _)| !old_stats_deduped.contains_key::<str>(new_key))
-        .for_each(|(new_key, new_value)| {
-            println!("{new_key} 0 => {new_value}");
-        });
-
-    // list all changed counts (key is in both maps but value differs)
-    new_stats_deduped
-        .iter()
-        .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::<str>(new_key))
-        .for_each(|(new_key, new_val)| {
-            let old_val = old_stats_deduped.get::<str>(new_key).unwrap();
-            println!("{new_key} {old_val} => {new_val}");
-        });
-
-    // list all gone counts (key is in old status but not in new stats)
-    old_stats_deduped
-        .iter()
-        .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key))
-        .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key))
-        .for_each(|(old_key, old_value)| {
-            println!("{old_key} {old_value} => 0");
-        });
-}
-
-/// Create necessary directories to run the lintcheck tool.
-///
-/// # Panics
-///
-/// This function panics if creating one of the dirs fails.
-fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
-    fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
-        assert_eq!(
-            err.kind(),
-            ErrorKind::AlreadyExists,
-            "cannot create lintcheck target dir"
-        );
-    });
-    fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
-        assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir");
-    });
-    fs::create_dir(extract_dir).unwrap_or_else(|err| {
-        assert_eq!(
-            err.kind(),
-            ErrorKind::AlreadyExists,
-            "cannot create crate extraction dir"
-        );
-    });
-}
-
 /// Returns the path to the Clippy project directory
 #[must_use]
 fn clippy_project_root() -> &'static Path {
diff --git a/src/tools/clippy/lintcheck/src/output.rs b/src/tools/clippy/lintcheck/src/output.rs
new file mode 100644
index 00000000000..4bfc554ef9e
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/output.rs
@@ -0,0 +1,235 @@
+use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan};
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::fmt::{self, Write as _};
+use std::fs;
+use std::path::Path;
+use std::process::ExitStatus;
+
+use crate::config::{LintcheckConfig, OutputFormat};
+
+/// A single emitted output from clippy being executed on a crate. It may either be a
+/// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many
+/// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution).
+#[derive(Debug)]
+pub enum ClippyCheckOutput {
+    ClippyWarning(ClippyWarning),
+    RustcIce(RustcIce),
+}
+
+#[derive(Debug)]
+pub struct RustcIce {
+    pub crate_name: String,
+    pub ice_content: String,
+}
+
+impl fmt::Display for RustcIce {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}:\n{}\n========================================\n",
+            self.crate_name, self.ice_content
+        )
+    }
+}
+
+impl RustcIce {
+    pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option<Self> {
+        if status.code().unwrap_or(0) == 101
+        /* ice exit status */
+        {
+            Some(Self {
+                crate_name: crate_name.to_owned(),
+                ice_content: stderr.to_owned(),
+            })
+        } else {
+            None
+        }
+    }
+}
+
+/// A single warning that clippy issued while checking a `Crate`
+#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct ClippyWarning {
+    pub lint: String,
+    pub diag: Diagnostic,
+}
+
+#[allow(unused)]
+impl ClippyWarning {
+    pub fn new(mut diag: Diagnostic) -> Option<Self> {
+        let lint = diag.code.clone()?.code;
+        if !(lint.contains("clippy") || diag.message.contains("clippy"))
+            || diag.message.contains("could not read cargo metadata")
+        {
+            return None;
+        }
+
+        // --recursive bypasses cargo so we have to strip the rendered output ourselves
+        let rendered = diag.rendered.as_mut().unwrap();
+        *rendered = strip_ansi_escapes::strip_str(&rendered);
+
+        Some(Self { lint, diag })
+    }
+
+    pub fn span(&self) -> &DiagnosticSpan {
+        self.diag.spans.iter().find(|span| span.is_primary).unwrap()
+    }
+
+    pub fn to_output(&self, format: OutputFormat) -> String {
+        let span = self.span();
+        let mut file = span.file_name.clone();
+        let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end);
+        match format {
+            OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message),
+            OutputFormat::Markdown => {
+                if file.starts_with("target") {
+                    file.insert_str(0, "../");
+                }
+
+                let mut output = String::from("| ");
+                write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap();
+                write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap();
+                output.push('\n');
+                output
+            },
+            OutputFormat::Json => unreachable!("JSON output is handled via serde"),
+        }
+    }
+}
+
+/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`]
+pub fn summarize_and_print_changes(
+    warnings: &[ClippyWarning],
+    ices: &[RustcIce],
+    clippy_ver: String,
+    config: &LintcheckConfig,
+) -> String {
+    // generate some stats
+    let (stats_formatted, new_stats) = gather_stats(warnings);
+    let old_stats = read_stats_from_file(&config.lintcheck_results_path);
+
+    let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.format)).collect();
+    all_msgs.sort();
+    all_msgs.push("\n\n### Stats:\n\n".into());
+    all_msgs.push(stats_formatted);
+
+    let mut text = clippy_ver; // clippy version number on top
+    text.push_str("\n### Reports\n\n");
+    if config.format == OutputFormat::Markdown {
+        text.push_str("| file | lint | message |\n");
+        text.push_str("| --- | --- | --- |\n");
+    }
+    write!(text, "{}", all_msgs.join("")).unwrap();
+    text.push_str("\n\n### ICEs:\n");
+    for ice in ices {
+        writeln!(text, "{ice}").unwrap();
+    }
+
+    print_stats(old_stats, new_stats, &config.lint_filter);
+
+    text
+}
+
+/// Generate a short list of occurring lints-types and their count
+fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
+    // count lint type occurrences
+    let mut counter: HashMap<&String, usize> = HashMap::new();
+    warnings
+        .iter()
+        .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1);
+
+    // collect into a tupled list for sorting
+    let mut stats: Vec<(&&String, &usize)> = counter.iter().collect();
+    // sort by "000{count} {clippy::lintname}"
+    // to not have a lint with 200 and 2 warnings take the same spot
+    stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}"));
+
+    let mut header = String::from("| lint                                               | count |\n");
+    header.push_str("| -------------------------------------------------- | ----- |\n");
+    let stats_string = stats
+        .iter()
+        .map(|(lint, count)| format!("| {lint:<50} |  {count:>4} |\n"))
+        .fold(header, |mut table, line| {
+            table.push_str(&line);
+            table
+        });
+
+    (stats_string, counter)
+}
+
+/// read the previous stats from the lintcheck-log file
+fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
+    let file_content: String = match fs::read_to_string(file_path).ok() {
+        Some(content) => content,
+        None => {
+            return HashMap::new();
+        },
+    };
+
+    let lines: Vec<String> = file_content.lines().map(ToString::to_string).collect();
+
+    lines
+        .iter()
+        .skip_while(|line| line.as_str() != "### Stats:")
+        // Skipping the table header and the `Stats:` label
+        .skip(4)
+        .take_while(|line| line.starts_with("| "))
+        .filter_map(|line| {
+            let mut spl = line.split('|');
+            // Skip the first `|` symbol
+            spl.next();
+            if let (Some(lint), Some(count)) = (spl.next(), spl.next()) {
+                Some((lint.trim().to_string(), count.trim().parse::<usize>().unwrap()))
+            } else {
+                None
+            }
+        })
+        .collect::<HashMap<String, usize>>()
+}
+
+/// print how lint counts changed between runs
+fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &[String]) {
+    let same_in_both_hashmaps = old_stats
+        .iter()
+        .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val))
+        .map(|(k, v)| (k.to_string(), *v))
+        .collect::<Vec<(String, usize)>>();
+
+    let mut old_stats_deduped = old_stats;
+    let mut new_stats_deduped = new_stats;
+
+    // remove duplicates from both hashmaps
+    for (k, v) in &same_in_both_hashmaps {
+        assert!(old_stats_deduped.remove(k) == Some(*v));
+        assert!(new_stats_deduped.remove(k) == Some(*v));
+    }
+
+    println!("\nStats:");
+
+    // list all new counts  (key is in new stats but not in old stats)
+    new_stats_deduped
+        .iter()
+        .filter(|(new_key, _)| !old_stats_deduped.contains_key::<str>(new_key))
+        .for_each(|(new_key, new_value)| {
+            println!("{new_key} 0 => {new_value}");
+        });
+
+    // list all changed counts (key is in both maps but value differs)
+    new_stats_deduped
+        .iter()
+        .filter(|(new_key, _new_val)| old_stats_deduped.contains_key::<str>(new_key))
+        .for_each(|(new_key, new_val)| {
+            let old_val = old_stats_deduped.get::<str>(new_key).unwrap();
+            println!("{new_key} {old_val} => {new_val}");
+        });
+
+    // list all gone counts (key is in old status but not in new stats)
+    old_stats_deduped
+        .iter()
+        .filter(|(old_key, _)| !new_stats_deduped.contains_key::<&String>(old_key))
+        .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key))
+        .for_each(|(old_key, old_value)| {
+            println!("{old_key} {old_value} => 0");
+        });
+}
diff --git a/src/tools/clippy/lintcheck/src/popular_crates.rs b/src/tools/clippy/lintcheck/src/popular_crates.rs
index 880a8bd81f0..ad8fc440c42 100644
--- a/src/tools/clippy/lintcheck/src/popular_crates.rs
+++ b/src/tools/clippy/lintcheck/src/popular_crates.rs
@@ -44,7 +44,7 @@ pub(crate) fn fetch(output: PathBuf, number: usize) -> Result<(), Box<dyn Error>
 
     let mut out = "[crates]\n".to_string();
     for Crate { name, max_version } in crates {
-        writeln!(out, "{name} = {{ name = '{name}', versions = ['{max_version}'] }}").unwrap();
+        writeln!(out, "{name} = {{ name = '{name}', version = '{max_version}' }}").unwrap();
     }
     fs::write(output, out)?;
 
diff --git a/src/tools/clippy/lintcheck/src/recursive.rs b/src/tools/clippy/lintcheck/src/recursive.rs
index 994fa3c3b23..373ca6f9918 100644
--- a/src/tools/clippy/lintcheck/src/recursive.rs
+++ b/src/tools/clippy/lintcheck/src/recursive.rs
@@ -3,7 +3,8 @@
 //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running
 //! clippy on the crate to the server
 
-use crate::{ClippyWarning, RecursiveOptions};
+use crate::input::RecursiveOptions;
+use crate::ClippyWarning;
 
 use std::collections::HashSet;
 use std::io::{BufRead, BufReader, Read, Write};
@@ -19,8 +20,6 @@ use serde::{Deserialize, Serialize};
 #[derive(Debug, Eq, Hash, PartialEq, Clone, Serialize, Deserialize)]
 pub(crate) struct DriverInfo {
     pub package_name: String,
-    pub crate_name: String,
-    pub version: String,
 }
 
 pub(crate) fn serialize_line<T, W>(value: &T, writer: &mut W)
@@ -65,7 +64,7 @@ fn process_stream(
     let messages = stderr
         .lines()
         .filter_map(|json_msg| serde_json::from_str::<Diagnostic>(json_msg).ok())
-        .filter_map(|diag| ClippyWarning::new(diag, &driver_info.package_name, &driver_info.version));
+        .filter_map(ClippyWarning::new);
 
     for message in messages {
         sender.send(message).unwrap();
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 72b50d59f7e..a61c22c59f9 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,4 @@
 [toolchain]
-channel = "nightly-2024-06-27"
+channel = "nightly-2024-07-11"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
+profile = "minimal"
diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
index 1be4b665bcb..66eda44f745 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
@@ -1,22 +1,18 @@
 error: use of a disallowed method `rustc_lint::context::LintContext::span_lint`
-  --> tests/ui-internal/disallow_span_lint.rs:14:5
+  --> tests/ui-internal/disallow_span_lint.rs:14:8
    |
-LL | /     cx.span_lint(lint, span, |lint| {
-LL | |         lint.primary_message(msg);
-LL | |     });
-   | |______^
+LL |     cx.span_lint(lint, span, |lint| {
+   |        ^^^^^^^^^
    |
    = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead (from clippy.toml)
    = note: `-D clippy::disallowed-methods` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
 
 error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint`
-  --> tests/ui-internal/disallow_span_lint.rs:20:5
+  --> tests/ui-internal/disallow_span_lint.rs:20:9
    |
-LL | /     tcx.node_span_lint(lint, hir_id, span, |lint| {
-LL | |         lint.primary_message(msg);
-LL | |     });
-   | |______^
+LL |     tcx.node_span_lint(lint, hir_id, span, |lint| {
+   |         ^^^^^^^^^^^^^^
    |
    = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml)
 
diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
index a74d8757e4a..016ee502c24 100644
--- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
@@ -1,4 +1,4 @@
-error: `std::string::String` may not be held across an `await` point per `clippy.toml`
+error: `std::string::String` may not be held across an await point per `clippy.toml`
   --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9
    |
 LL |     let _x = String::from("hello");
@@ -8,13 +8,13 @@ LL |     let _x = String::from("hello");
    = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]`
 
-error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml`
+error: `std::net::Ipv4Addr` may not be held across an await point per `clippy.toml`
   --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:10:9
    |
 LL |     let x = Ipv4Addr::new(127, 0, 0, 1);
    |         ^
 
-error: `std::string::String` may not be held across an `await` point per `clippy.toml`
+error: `std::string::String` may not be held across an await point per `clippy.toml`
   --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:33:13
    |
 LL |         let _x = String::from("hi!");
diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml
new file mode 100644
index 00000000000..cda8d17eed4
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/clippy.toml
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed
new file mode 100644
index 00000000000..40556ca5410
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed
@@ -0,0 +1,10 @@
+#![warn(clippy::needless_pass_by_ref_mut)]
+#![allow(clippy::ptr_arg)]
+
+// Should warn
+pub fn pub_foo(s: &Vec<u32>, b: &u32, x: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    *x += *b + s.len() as u32;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs
new file mode 100644
index 00000000000..bbc63ceb15a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs
@@ -0,0 +1,10 @@
+#![warn(clippy::needless_pass_by_ref_mut)]
+#![allow(clippy::ptr_arg)]
+
+// Should warn
+pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    *x += *b + s.len() as u32;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr
new file mode 100644
index 00000000000..c10607bf4ba
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr
@@ -0,0 +1,12 @@
+error: this argument is a mutable reference, but not used mutably
+  --> tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs:5:19
+   |
+LL | pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+   |                   ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
+   |
+   = warning: changing this function will impact semver compatibility
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index 4afbbf5f807..f661e76cc74 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -2,36 +2,36 @@ error: use of a disallowed method `regex::Regex::new`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:14
    |
 LL |     let re = Regex::new(r"ab.*c").unwrap();
-   |              ^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^
    |
    = note: `-D clippy::disallowed-methods` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
 
 error: use of a disallowed method `regex::Regex::is_match`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:8
    |
 LL |     re.is_match("abc");
-   |     ^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^
    |
    = note: no matching allowed (from clippy.toml)
 
 error: use of a disallowed method `std::iter::Iterator::sum`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14
    |
 LL |     a.iter().sum::<i32>();
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^
 
 error: use of a disallowed method `slice::sort_unstable`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:7
    |
 LL |     a.sort_unstable();
-   |     ^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:13
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:20
    |
 LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                    ^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47:61
@@ -55,37 +55,37 @@ error: use of a disallowed method `futures::stream::select_all`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:31
    |
 LL |     let same_name_as_module = select_all(vec![empty::<()>()]);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_fn`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5
    |
 LL |     local_fn();
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_mod::f`
   --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:5
    |
 LL |     local_mod::f();
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Struct::method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:7
    |
 LL |     s.method();
-   |     ^^^^^^^^^^
+   |       ^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:7
    |
 LL |     s.provided_method();
-   |     ^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:7
    |
 LL |     s.implemented_method();
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.rs b/src/tools/clippy/tests/ui/assertions_on_constants.rs
index 1309ae45d0a..957154e60de 100644
--- a/src/tools/clippy/tests/ui/assertions_on_constants.rs
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.rs
@@ -1,4 +1,4 @@
-#![allow(non_fmt_panics, clippy::needless_bool)]
+#![allow(non_fmt_panics, clippy::needless_bool, clippy::eq_op)]
 
 macro_rules! assert_const {
     ($len:expr) => {
@@ -49,7 +49,16 @@ fn main() {
     const _: () = assert!(true);
     //~^ ERROR: `assert!(true)` will be optimized out by the compiler
 
+    assert!(8 == (7 + 1));
+    //~^ ERROR: `assert!(true)` will be optimized out by the compiler
+
     // Don't lint if the value is dependent on a defined constant:
     const N: usize = 1024;
     const _: () = assert!(N.is_power_of_two());
 }
+
+const _: () = {
+    assert!(true);
+    //~^ ERROR: `assert!(true)` will be optimized out by the compiler
+    assert!(8 == (7 + 1));
+};
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
index 00f117c9492..e164a999c43 100644
--- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
@@ -80,5 +80,21 @@ LL |     const _: () = assert!(true);
    |
    = help: remove it
 
-error: aborting due to 10 previous errors
+error: `assert!(true)` will be optimized out by the compiler
+  --> tests/ui/assertions_on_constants.rs:52:5
+   |
+LL |     assert!(8 == (7 + 1));
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove it
+
+error: `assert!(true)` will be optimized out by the compiler
+  --> tests/ui/assertions_on_constants.rs:61:5
+   |
+LL |     assert!(true);
+   |     ^^^^^^^^^^^^^
+   |
+   = help: remove it
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.rs b/src/tools/clippy/tests/ui/await_holding_lock.rs
index 8e5510e6cd0..cecf00c934f 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.rs
+++ b/src/tools/clippy/tests/ui/await_holding_lock.rs
@@ -8,7 +8,7 @@ mod std_mutex {
 
     pub async fn bad(x: &Mutex<u32>) -> u32 {
         let guard = x.lock().unwrap();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
@@ -24,13 +24,13 @@ mod std_mutex {
 
     pub async fn bad_rw(x: &RwLock<u32>) -> u32 {
         let guard = x.read().unwrap();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
     pub async fn bad_rw_write(x: &RwLock<u32>) -> u32 {
         let mut guard = x.write().unwrap();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
@@ -52,7 +52,7 @@ mod std_mutex {
         let first = baz().await;
 
         let guard = x.lock().unwrap();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
 
         let second = baz().await;
 
@@ -66,7 +66,7 @@ mod std_mutex {
 
         let second = {
             let guard = x.lock().unwrap();
-            //~^ ERROR: this `MutexGuard` is held across an `await` point
+            //~^ ERROR: this `MutexGuard` is held across an await point
             baz().await
         };
 
@@ -79,7 +79,7 @@ mod std_mutex {
     pub fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
         async move {
             let guard = x.lock().unwrap();
-            //~^ ERROR: this `MutexGuard` is held across an `await` point
+            //~^ ERROR: this `MutexGuard` is held across an await point
             baz().await
         }
     }
@@ -92,7 +92,7 @@ mod parking_lot_mutex {
 
     pub async fn bad(x: &Mutex<u32>) -> u32 {
         let guard = x.lock();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
@@ -108,13 +108,13 @@ mod parking_lot_mutex {
 
     pub async fn bad_rw(x: &RwLock<u32>) -> u32 {
         let guard = x.read();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
     pub async fn bad_rw_write(x: &RwLock<u32>) -> u32 {
         let mut guard = x.write();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
         baz().await
     }
 
@@ -136,7 +136,7 @@ mod parking_lot_mutex {
         let first = baz().await;
 
         let guard = x.lock();
-        //~^ ERROR: this `MutexGuard` is held across an `await` point
+        //~^ ERROR: this `MutexGuard` is held across an await point
 
         let second = baz().await;
 
@@ -150,7 +150,7 @@ mod parking_lot_mutex {
 
         let second = {
             let guard = x.lock();
-            //~^ ERROR: this `MutexGuard` is held across an `await` point
+            //~^ ERROR: this `MutexGuard` is held across an await point
             baz().await
         };
 
@@ -163,7 +163,7 @@ mod parking_lot_mutex {
     pub fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
         async move {
             let guard = x.lock();
-            //~^ ERROR: this `MutexGuard` is held across an `await` point
+            //~^ ERROR: this `MutexGuard` is held across an await point
             baz().await
         }
     }
@@ -184,7 +184,7 @@ async fn no_await(x: std::sync::Mutex<u32>) {
 // `*guard += 1` is removed it is picked up.
 async fn dropped_before_await(x: std::sync::Mutex<u32>) {
     let mut guard = x.lock().unwrap();
-    //~^ ERROR: this `MutexGuard` is held across an `await` point
+    //~^ ERROR: this `MutexGuard` is held across an await point
     *guard += 1;
     drop(guard);
     baz().await;
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr
index 0af48a36acc..af61d893948 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.stderr
+++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr
@@ -1,11 +1,11 @@
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:10:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:12:15
    |
 LL |         baz().await
@@ -13,40 +13,40 @@ LL |         baz().await
    = note: `-D clippy::await-holding-lock` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]`
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:26:13
    |
 LL |         let guard = x.read().unwrap();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:28:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:32:13
    |
 LL |         let mut guard = x.write().unwrap();
    |             ^^^^^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:34:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:54:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:57:28
    |
 LL |         let second = baz().await;
@@ -55,79 +55,79 @@ LL |
 LL |         let third = baz().await;
    |                           ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:68:17
    |
 LL |             let guard = x.lock().unwrap();
    |                 ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:70:19
    |
 LL |             baz().await
    |                   ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:81:17
    |
 LL |             let guard = x.lock().unwrap();
    |                 ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:83:19
    |
 LL |             baz().await
    |                   ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:94:13
    |
 LL |         let guard = x.lock();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:96:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:110:13
    |
 LL |         let guard = x.read();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:112:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:116:13
    |
 LL |         let mut guard = x.write();
    |             ^^^^^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:118:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:138:13
    |
 LL |         let guard = x.lock();
    |             ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:141:28
    |
 LL |         let second = baz().await;
@@ -136,40 +136,40 @@ LL |
 LL |         let third = baz().await;
    |                           ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:152:17
    |
 LL |             let guard = x.lock();
    |                 ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:154:19
    |
 LL |             baz().await
    |                   ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:165:17
    |
 LL |             let guard = x.lock();
    |                 ^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:167:19
    |
 LL |             baz().await
    |                   ^^^^^
 
-error: this `MutexGuard` is held across an `await` point
+error: this `MutexGuard` is held across an await point
   --> tests/ui/await_holding_lock.rs:186:9
    |
 LL |     let mut guard = x.lock().unwrap();
    |         ^^^^^^^^^
    |
-   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
-note: these are all the `await` points this lock is held through
+   = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling `await`
+note: these are all the await points this lock is held through
   --> tests/ui/await_holding_lock.rs:190:11
    |
 LL |     baz().await;
diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs
index 5bd26c62836..b0c92d8c1f6 100644
--- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs
+++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs
@@ -4,13 +4,13 @@ use std::cell::RefCell;
 
 async fn bad(x: &RefCell<u32>) -> u32 {
     let b = x.borrow();
-    //~^ ERROR: this `RefCell` reference is held across an `await` point
+    //~^ ERROR: this `RefCell` reference is held across an await point
     baz().await
 }
 
 async fn bad_mut(x: &RefCell<u32>) -> u32 {
     let b = x.borrow_mut();
-    //~^ ERROR: this `RefCell` reference is held across an `await` point
+    //~^ ERROR: this `RefCell` reference is held across an await point
     baz().await
 }
 
@@ -32,7 +32,7 @@ async fn also_bad(x: &RefCell<u32>) -> u32 {
     let first = baz().await;
 
     let b = x.borrow_mut();
-    //~^ ERROR: this `RefCell` reference is held across an `await` point
+    //~^ ERROR: this `RefCell` reference is held across an await point
 
     let second = baz().await;
 
@@ -45,7 +45,7 @@ async fn less_bad(x: &RefCell<u32>) -> u32 {
     let first = baz().await;
 
     let b = x.borrow_mut();
-    //~^ ERROR: this `RefCell` reference is held across an `await` point
+    //~^ ERROR: this `RefCell` reference is held across an await point
 
     let second = baz().await;
 
@@ -61,7 +61,7 @@ async fn not_good(x: &RefCell<u32>) -> u32 {
 
     let second = {
         let b = x.borrow_mut();
-        //~^ ERROR: this `RefCell` reference is held across an `await` point
+        //~^ ERROR: this `RefCell` reference is held across an await point
         baz().await
     };
 
@@ -74,7 +74,7 @@ async fn not_good(x: &RefCell<u32>) -> u32 {
 fn block_bad(x: &RefCell<u32>) -> impl std::future::Future<Output = u32> + '_ {
     async move {
         let b = x.borrow_mut();
-        //~^ ERROR: this `RefCell` reference is held across an `await` point
+        //~^ ERROR: this `RefCell` reference is held across an await point
         baz().await
     }
 }
diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
index 6b474c27ddc..6c7209c9ff9 100644
--- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
+++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
@@ -1,11 +1,11 @@
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:6:9
    |
 LL |     let b = x.borrow();
    |         ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:8:11
    |
 LL |     baz().await
@@ -13,27 +13,27 @@ LL |     baz().await
    = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]`
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:12:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:14:11
    |
 LL |     baz().await
    |           ^^^^^
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:34:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:37:24
    |
 LL |     let second = baz().await;
@@ -42,40 +42,40 @@ LL |
 LL |     let third = baz().await;
    |                       ^^^^^
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:47:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:50:24
    |
 LL |     let second = baz().await;
    |                        ^^^^^
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:63:13
    |
 LL |         let b = x.borrow_mut();
    |             ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:65:15
    |
 LL |         baz().await
    |               ^^^^^
 
-error: this `RefCell` reference is held across an `await` point
+error: this `RefCell` reference is held across an await point
   --> tests/ui/await_holding_refcell_ref.rs:76:13
    |
 LL |         let b = x.borrow_mut();
    |             ^
    |
    = help: ensure the reference is dropped before calling `await`
-note: these are all the `await` points this reference is held through
+note: these are all the await points this reference is held through
   --> tests/ui/await_holding_refcell_ref.rs:78:15
    |
 LL |         baz().await
diff --git a/src/tools/clippy/tests/ui/byte_char_slices.fixed b/src/tools/clippy/tests/ui/byte_char_slices.fixed
new file mode 100644
index 00000000000..d1db58f9363
--- /dev/null
+++ b/src/tools/clippy/tests/ui/byte_char_slices.fixed
@@ -0,0 +1,13 @@
+#![allow(unused)]
+#![warn(clippy::byte_char_slices)]
+
+fn main() {
+    let bad = b"abc";
+    let quotes = b"\"Hi";
+    let quotes = b"'Sup";
+    let escapes = b"\x42Esc";
+
+    let good = &[b'a', 0x42];
+    let good = [b'a', b'a'];
+    let good: u8 = [b'a', b'c'].into_iter().sum();
+}
diff --git a/src/tools/clippy/tests/ui/byte_char_slices.rs b/src/tools/clippy/tests/ui/byte_char_slices.rs
new file mode 100644
index 00000000000..18648fffceb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/byte_char_slices.rs
@@ -0,0 +1,13 @@
+#![allow(unused)]
+#![warn(clippy::byte_char_slices)]
+
+fn main() {
+    let bad = &[b'a', b'b', b'c'];
+    let quotes = &[b'"', b'H', b'i'];
+    let quotes = &[b'\'', b'S', b'u', b'p'];
+    let escapes = &[b'\x42', b'E', b's', b'c'];
+
+    let good = &[b'a', 0x42];
+    let good = vec![b'a', b'a'];
+    let good: u8 = [b'a', b'c'].into_iter().sum();
+}
diff --git a/src/tools/clippy/tests/ui/byte_char_slices.stderr b/src/tools/clippy/tests/ui/byte_char_slices.stderr
new file mode 100644
index 00000000000..4e2b5d8a732
--- /dev/null
+++ b/src/tools/clippy/tests/ui/byte_char_slices.stderr
@@ -0,0 +1,38 @@
+error: can be more succinctly written as a byte str
+  --> tests/ui/byte_char_slices.rs:5:15
+   |
+LL |     let bad = &[b'a', b'b', b'c'];
+   |               ^^^^^^^^^^^^^^^^^^^ help: try: `b"abc"`
+   |
+   = note: `-D clippy::byte-char-slices` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]`
+
+error: can be more succinctly written as a byte str
+  --> tests/ui/byte_char_slices.rs:6:18
+   |
+LL |     let quotes = &[b'"', b'H', b'i'];
+   |                  ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"`
+
+error: can be more succinctly written as a byte str
+  --> tests/ui/byte_char_slices.rs:7:18
+   |
+LL |     let quotes = &[b'\'', b'S', b'u', b'p'];
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"`
+
+error: can be more succinctly written as a byte str
+  --> tests/ui/byte_char_slices.rs:8:19
+   |
+LL |     let escapes = &[b'\x42', b'E', b's', b'c'];
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"`
+
+error: useless use of `vec!`
+  --> tests/ui/byte_char_slices.rs:11:16
+   |
+LL |     let good = vec![b'a', b'a'];
+   |                ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']`
+   |
+   = note: `-D clippy::useless-vec` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cfg_not_test.rs b/src/tools/clippy/tests/ui/cfg_not_test.rs
new file mode 100644
index 00000000000..da3e29d2896
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cfg_not_test.rs
@@ -0,0 +1,32 @@
+#![allow(unused)]
+#![warn(clippy::cfg_not_test)]
+
+fn important_check() {}
+
+fn main() {
+    // Statement
+    #[cfg(not(test))]
+    let answer = 42;
+
+    // Expression
+    #[cfg(not(test))]
+    important_check();
+
+    // Make sure only not(test) are checked, not other attributes
+    #[cfg(not(foo))]
+    important_check();
+}
+
+#[cfg(not(not(test)))]
+struct CfgNotTest;
+
+// Deeply nested `not(test)`
+#[cfg(not(test))]
+fn foo() {}
+#[cfg(all(debug_assertions, not(test)))]
+fn bar() {}
+#[cfg(not(any(not(debug_assertions), test)))]
+fn baz() {}
+
+#[cfg(test)]
+mod tests {}
diff --git a/src/tools/clippy/tests/ui/cfg_not_test.stderr b/src/tools/clippy/tests/ui/cfg_not_test.stderr
new file mode 100644
index 00000000000..c1bf626887a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cfg_not_test.stderr
@@ -0,0 +1,45 @@
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:8:5
+   |
+LL |     #[cfg(not(test))]
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+   = note: this could increase code coverage despite not actually being tested
+   = note: `-D clippy::cfg-not-test` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::cfg_not_test)]`
+
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:12:5
+   |
+LL |     #[cfg(not(test))]
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:24:1
+   |
+LL | #[cfg(not(test))]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:26:1
+   |
+LL | #[cfg(all(debug_assertions, not(test)))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+
+error: code is excluded from test builds
+  --> tests/ui/cfg_not_test.rs:28:1
+   |
+LL | #[cfg(not(any(not(debug_assertions), test)))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider not excluding any code from test builds
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
index c7cf5cf5483..a84a945a429 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr
@@ -1,4 +1,4 @@
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/crashes/ice-12616.rs:6:5
    |
 LL |     s() as *const ();
diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs
index 13c883409bf..96531bf8d88 100644
--- a/src/tools/clippy/tests/ui/disallowed_names.rs
+++ b/src/tools/clippy/tests/ui/disallowed_names.rs
@@ -60,6 +60,7 @@ fn issue_1647_ref_mut() {
     //~^ ERROR: use of a disallowed/placeholder name `quux`
 }
 
+#[cfg(test)]
 mod tests {
     fn issue_7305() {
         // `disallowed_names` lint should not be triggered inside of the test code.
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed
new file mode 100644
index 00000000000..1aaa26afe7f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.fixed
@@ -0,0 +1,47 @@
+// https://github.com/rust-lang/rust-clippy/issues/12917
+#![warn(clippy::doc_lazy_continuation)]
+
+/// This is a constant.
+///
+/// The meaning of which should not be explained.
+pub const A: i32 = 42;
+
+/// This is another constant, no longer used.
+///
+/// This block of documentation has a long
+/// explanation and derivation to explain
+/// why it is what it is, and how it's used.
+///
+/// It is left here for historical reasons, and
+/// for reference.
+///
+/// Reasons it's great:
+///  - First reason
+///  - Second reason
+///
+//pub const B: i32 = 1337;
+
+/// This is yet another constant.
+///
+/// This has a similar fate as `B`.
+///
+/// Reasons it's useful:
+///  1. First reason
+///  2. Second reason
+///
+//pub const C: i32 = 8008;
+
+/// This is still in use.
+pub const D: i32 = 20;
+
+/// > blockquote code path
+///
+
+/// bottom text
+pub const E: i32 = 20;
+
+/// > blockquote code path
+///
+#[repr(C)]
+/// bottom text
+pub struct Foo(i32);
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs
new file mode 100644
index 00000000000..e1ab8fc8389
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.rs
@@ -0,0 +1,43 @@
+// https://github.com/rust-lang/rust-clippy/issues/12917
+#![warn(clippy::doc_lazy_continuation)]
+
+/// This is a constant.
+///
+/// The meaning of which should not be explained.
+pub const A: i32 = 42;
+
+/// This is another constant, no longer used.
+///
+/// This block of documentation has a long
+/// explanation and derivation to explain
+/// why it is what it is, and how it's used.
+///
+/// It is left here for historical reasons, and
+/// for reference.
+///
+/// Reasons it's great:
+///  - First reason
+///  - Second reason
+//pub const B: i32 = 1337;
+
+/// This is yet another constant.
+///
+/// This has a similar fate as `B`.
+///
+/// Reasons it's useful:
+///  1. First reason
+///  2. Second reason
+//pub const C: i32 = 8008;
+
+/// This is still in use.
+pub const D: i32 = 20;
+
+/// > blockquote code path
+
+/// bottom text
+pub const E: i32 = 20;
+
+/// > blockquote code path
+#[repr(C)]
+/// bottom text
+pub struct Foo(i32);
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr
new file mode 100644
index 00000000000..854906a7474
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blank_line.stderr
@@ -0,0 +1,56 @@
+error: doc list item without indentation
+  --> tests/ui/doc/doc_lazy_blank_line.rs:23:5
+   |
+LL | /// This is yet another constant.
+   |     ^
+   |
+   = help: if this is intended to be part of the list, indent 3 spaces
+   = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]`
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ ///  - Second reason
+LL + ///
+   |
+
+error: doc list item without indentation
+  --> tests/ui/doc/doc_lazy_blank_line.rs:32:5
+   |
+LL | /// This is still in use.
+   |     ^
+   |
+   = help: if this is intended to be part of the list, indent 4 spaces
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ ///  2. Second reason
+LL + ///
+   |
+
+error: doc quote line without `>` marker
+  --> tests/ui/doc/doc_lazy_blank_line.rs:37:5
+   |
+LL | /// bottom text
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// > blockquote code path
+LL + ///
+   |
+
+error: doc quote line without `>` marker
+  --> tests/ui/doc/doc_lazy_blank_line.rs:42:5
+   |
+LL | /// bottom text
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// > blockquote code path
+LL + ///
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
index 9877991f183..9d6e8637608 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
@@ -2,7 +2,7 @@
 
 /// > blockquote with
 /// > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn first() {}
 
 /// > blockquote with no
@@ -18,24 +18,24 @@ fn two_nowarn() {}
 /// >
 /// > > nest here
 /// > > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn two() {}
 
 /// > nest here
 /// >
 /// > > nest here
 /// > > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn three() {}
 
 /// >   * > nest here
 /// >     > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn four() {}
 
 /// > * > nest here
 /// >   > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn four_point_1() {}
 
 /// * > nest here lazy continuation
@@ -43,5 +43,5 @@ fn five() {}
 
 /// 1. > nest here
 ///    > lazy continuation (this results in strange indentation, but still works)
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn six() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
index 587b2fdd533..0323a1b44e7 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
@@ -2,7 +2,7 @@
 
 /// > blockquote with
 /// lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn first() {}
 
 /// > blockquote with no
@@ -18,24 +18,24 @@ fn two_nowarn() {}
 /// >
 /// > > nest here
 /// > lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn two() {}
 
 /// > nest here
 /// >
 /// > > nest here
 /// lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn three() {}
 
 /// >   * > nest here
 /// lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn four() {}
 
 /// > * > nest here
 /// lazy continuation
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn four_point_1() {}
 
 /// * > nest here lazy continuation
@@ -43,5 +43,5 @@ fn five() {}
 
 /// 1. > nest here
 ///  lazy continuation (this results in strange indentation, but still works)
-//~^ ERROR: doc quote missing `>` marker
+//~^ ERROR: doc quote line without `>` marker
 fn six() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
index 975184a01c3..d3390efdff3 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
@@ -1,4 +1,4 @@
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:4:5
    |
 LL | /// lazy continuation
@@ -12,7 +12,7 @@ help: add markers to start of line
 LL | /// > lazy continuation
    |     +
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:20:5
    |
 LL | /// > lazy continuation
@@ -24,7 +24,7 @@ help: add markers to start of line
 LL | /// > > lazy continuation
    |       +
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:27:5
    |
 LL | /// lazy continuation
@@ -36,7 +36,7 @@ help: add markers to start of line
 LL | /// > > lazy continuation
    |     +++
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:32:5
    |
 LL | /// lazy continuation
@@ -48,7 +48,7 @@ help: add markers to start of line
 LL | /// >     > lazy continuation
    |     +++++++
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:37:5
    |
 LL | /// lazy continuation
@@ -60,7 +60,7 @@ help: add markers to start of line
 LL | /// >   > lazy continuation
    |     +++++
 
-error: doc quote missing `>` marker
+error: doc quote line without `>` marker
   --> tests/ui/doc/doc_lazy_blockquote.rs:45:5
    |
 LL | ///  lazy continuation (this results in strange indentation, but still works)
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
index 409e6b0bc22..ea59ae4c01c 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
@@ -2,38 +2,41 @@
 
 /// 1. nest here
 ///    lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn one() {}
 
 /// 1. first line
 ///    lazy list continuations don't make warnings with this lint
-//~^ ERROR: doc list item missing indentation
-///    because they don't have the
-//~^ ERROR: doc list item missing indentation
+///
+//~^ ERROR: doc list item without indentation
+/// because they don't have the
+//~^ ERROR: doc list item without indentation
 fn two() {}
 
 ///   - nest here
 ///     lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn three() {}
 
 ///   - first line
 ///     lazy list continuations don't make warnings with this lint
-//~^ ERROR: doc list item missing indentation
-///     because they don't have the
-//~^ ERROR: doc list item missing indentation
+///
+//~^ ERROR: doc list item without indentation
+/// because they don't have the
+//~^ ERROR: doc list item without indentation
 fn four() {}
 
 ///   - nest here
 ///     lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn five() {}
 
 ///   - - first line
 ///       this will warn on the lazy continuation
-//~^ ERROR: doc list item missing indentation
-///       and so should this
-//~^ ERROR: doc list item missing indentation
+///
+//~^ ERROR: doc list item without indentation
+///     and so should this
+//~^ ERROR: doc list item without indentation
 fn six() {}
 
 ///   - - first line
@@ -54,7 +57,7 @@ fn seven() {}
 /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
 ///     to set up. Example:
 ///   'protocol_descriptors': [
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 ///      {
 ///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
 ///          'params': [
@@ -73,5 +76,5 @@ fn seven() {}
 ///          }]
 ///      }
 ///   ]
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn eight() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
index 30ab448a113..3cc18e35780 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
@@ -2,38 +2,38 @@
 
 /// 1. nest here
 /// lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn one() {}
 
 /// 1. first line
 /// lazy list continuations don't make warnings with this lint
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 /// because they don't have the
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn two() {}
 
 ///   - nest here
 /// lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn three() {}
 
 ///   - first line
 /// lazy list continuations don't make warnings with this lint
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 /// because they don't have the
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn four() {}
 
 ///   - nest here
 /// lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn five() {}
 
 ///   - - first line
 /// this will warn on the lazy continuation
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 ///     and so should this
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn six() {}
 
 ///   - - first line
@@ -54,7 +54,7 @@ fn seven() {}
 /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
 ///     to set up. Example:
 ///  'protocol_descriptors': [
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 ///      {
 ///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
 ///          'params': [
@@ -73,5 +73,5 @@ fn seven() {}
 ///          }]
 ///      }
 ///  ]
-//~^ ERROR: doc list item missing indentation
+//~^ ERROR: doc list item without indentation
 fn eight() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
index ddfdc49340c..52aa74df894 100644
--- a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
@@ -1,4 +1,4 @@
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:4:5
    |
 LL | /// lazy continuation
@@ -12,7 +12,7 @@ help: indent this line
 LL | ///    lazy continuation
    |     +++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:9:5
    |
 LL | /// lazy list continuations don't make warnings with this lint
@@ -24,19 +24,20 @@ help: indent this line
 LL | ///    lazy list continuations don't make warnings with this lint
    |     +++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:11:5
    |
 LL | /// because they don't have the
    |     ^
    |
-   = help: if this is supposed to be its own paragraph, add a blank line
-help: indent this line
+   = help: if this is intended to be part of the list, indent 3 spaces
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// lazy list continuations don't make warnings with this lint
+LL + ///
    |
-LL | ///    because they don't have the
-   |     +++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:16:5
    |
 LL | /// lazy continuation
@@ -48,7 +49,7 @@ help: indent this line
 LL | ///     lazy continuation
    |     ++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:21:5
    |
 LL | /// lazy list continuations don't make warnings with this lint
@@ -60,19 +61,20 @@ help: indent this line
 LL | ///     lazy list continuations don't make warnings with this lint
    |     ++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:23:5
    |
 LL | /// because they don't have the
    |     ^
    |
-   = help: if this is supposed to be its own paragraph, add a blank line
-help: indent this line
+   = help: if this is intended to be part of the list, indent 4 spaces
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// lazy list continuations don't make warnings with this lint
+LL + ///
    |
-LL | ///     because they don't have the
-   |     ++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:28:5
    |
 LL | /// lazy continuation
@@ -84,7 +86,7 @@ help: indent this line
 LL | ///     lazy continuation
    |     ++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:33:5
    |
 LL | /// this will warn on the lazy continuation
@@ -96,19 +98,20 @@ help: indent this line
 LL | ///       this will warn on the lazy continuation
    |     ++++++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:35:5
    |
 LL | ///     and so should this
    |     ^^^^
    |
-   = help: if this is supposed to be its own paragraph, add a blank line
-help: indent this line
+   = help: if this is intended to be part of the list, indent 2 spaces
+help: if this should be its own paragraph, add a blank doc comment line
+   |
+LL ~ /// this will warn on the lazy continuation
+LL + ///
    |
-LL | ///       and so should this
-   |         ++
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:56:5
    |
 LL | ///  'protocol_descriptors': [
@@ -120,7 +123,7 @@ help: indent this line
 LL | ///   'protocol_descriptors': [
    |      +
 
-error: doc list item missing indentation
+error: doc list item without indentation
   --> tests/ui/doc/doc_lazy_list.rs:75:5
    |
 LL | ///  ]
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
index 6f7bab72040..04446787b6c 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
@@ -49,3 +49,20 @@ fn other_markdown() {}
 ///   pub struct Struct;
 ///   ```
 fn issue_7421() {}
+
+/// `
+//~^ ERROR: backticks are unbalanced
+fn escape_0() {}
+
+/// Escaped \` backticks don't count.
+fn escape_1() {}
+
+/// Escaped \` \` backticks don't count.
+fn escape_2() {}
+
+/// Escaped \` ` backticks don't count, but unescaped backticks do.
+//~^ ERROR: backticks are unbalanced
+fn escape_3() {}
+
+/// Backslashes ` \` within code blocks don't count.
+fn escape_4() {}
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
index 56ef2913623..50324010e97 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
@@ -78,5 +78,21 @@ help: try
 LL | /// - This item needs `backticks_here`
    |                       ~~~~~~~~~~~~~~~~
 
-error: aborting due to 8 previous errors
+error: backticks are unbalanced
+  --> tests/ui/doc/unbalanced_ticks.rs:53:5
+   |
+LL | /// `
+   |     ^
+   |
+   = help: a backtick may be missing a pair
+
+error: backticks are unbalanced
+  --> tests/ui/doc/unbalanced_ticks.rs:63:5
+   |
+LL | /// Escaped \` ` backticks don't count, but unescaped backticks do.
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: a backtick may be missing a pair
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index e6ca4bb66cc..255b2c5a220 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -345,3 +345,39 @@ fn main() {
         let _ = &mut ({ *x.u }).x;
     }
 }
+
+mod issue_12969 {
+    use std::ops::Deref;
+
+    struct Wrapper<T>(T);
+
+    impl<T> Deref for Wrapper<T> {
+        type Target = T;
+
+        fn deref(&self) -> &T {
+            &self.0
+        }
+    }
+
+    fn foo(_bar: &str) {}
+
+    fn bar() {
+        let wrapped_bar = Wrapper("");
+
+        foo(&wrapped_bar);
+    }
+}
+
+mod issue_9841 {
+    fn takes_array_ref<T, const N: usize>(array: &&[T; N]) {
+        takes_slice(*array)
+    }
+
+    fn takes_array_ref_ref<T, const N: usize>(array: &&&[T; N]) {
+        takes_slice(**array)
+    }
+
+    fn takes_slice<T>(slice: &[T]) {
+        todo!()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index 7531e1f87b7..99906999f01 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -345,3 +345,39 @@ fn main() {
         let _ = &mut ({ *x.u }).x;
     }
 }
+
+mod issue_12969 {
+    use std::ops::Deref;
+
+    struct Wrapper<T>(T);
+
+    impl<T> Deref for Wrapper<T> {
+        type Target = T;
+
+        fn deref(&self) -> &T {
+            &self.0
+        }
+    }
+
+    fn foo(_bar: &str) {}
+
+    fn bar() {
+        let wrapped_bar = Wrapper("");
+
+        foo(&*wrapped_bar);
+    }
+}
+
+mod issue_9841 {
+    fn takes_array_ref<T, const N: usize>(array: &&[T; N]) {
+        takes_slice(*array)
+    }
+
+    fn takes_array_ref_ref<T, const N: usize>(array: &&&[T; N]) {
+        takes_slice(**array)
+    }
+
+    fn takes_slice<T>(slice: &[T]) {
+        todo!()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
index 56a183de348..53784934f63 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
@@ -271,5 +271,11 @@ error: deref which would be done by auto-deref
 LL |         let _ = &mut (*{ x.u }).x;
    |                      ^^^^^^^^^^ help: try: `{ x.u }`
 
-error: aborting due to 45 previous errors
+error: deref which would be done by auto-deref
+  --> tests/ui/explicit_auto_deref.rs:367:13
+   |
+LL |         foo(&*wrapped_bar);
+   |             ^^^^^^^^^^^^^ help: try: `&wrapped_bar`
+
+error: aborting due to 46 previous errors
 
diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs
index 1923ad7c677..78dd2c6c01c 100644
--- a/src/tools/clippy/tests/ui/float_cmp.rs
+++ b/src/tools/clippy/tests/ui/float_cmp.rs
@@ -71,19 +71,16 @@ fn main() {
     twice(ONE) != ONE;
     ONE as f64 != 2.0;
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     ONE as f64 != 0.0; // no error, comparison with zero is ok
 
     let x: f64 = 1.0;
 
     x == 1.0;
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     x != 0f64; // no error, comparison with zero is ok
 
     twice(x) != twice(ONE as f64);
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     x < 0.0; // no errors, lower or greater comparisons need no fuzzyness
     x > 0.0;
@@ -105,17 +102,14 @@ fn main() {
     ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i
     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     let a1: [f32; 1] = [0.0];
     let a2: [f32; 1] = [1.1];
 
     a1 == a2;
     //~^ ERROR: strict comparison of `f32` or `f64` arrays
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     a1[0] == a2[0];
     //~^ ERROR: strict comparison of `f32` or `f64`
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     // no errors - comparing signums is ok
     let x32 = 3.21f32;
diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr
index c8a0bde6e63..d10da8a99a9 100644
--- a/src/tools/clippy/tests/ui/float_cmp.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp.stderr
@@ -4,49 +4,38 @@ error: strict comparison of `f32` or `f64`
 LL |     ONE as f64 != 2.0;
    |     ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
    = note: `-D clippy::float-cmp` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:79:5
+  --> tests/ui/float_cmp.rs:78:5
    |
 LL |     x == 1.0;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:84:5
+  --> tests/ui/float_cmp.rs:82:5
    |
 LL |     twice(x) != twice(ONE as f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:106:5
+  --> tests/ui/float_cmp.rs:103:5
    |
 LL |     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` arrays
-  --> tests/ui/float_cmp.rs:113:5
+  --> tests/ui/float_cmp.rs:109:5
    |
 LL |     a1 == a2;
    |     ^^^^^^^^
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:116:5
+  --> tests/ui/float_cmp.rs:111:5
    |
 LL |     a1[0] == a2[0];
    |     ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.rs b/src/tools/clippy/tests/ui/float_cmp_const.rs
index 47ea0e19c68..08180556437 100644
--- a/src/tools/clippy/tests/ui/float_cmp_const.rs
+++ b/src/tools/clippy/tests/ui/float_cmp_const.rs
@@ -15,28 +15,21 @@ fn main() {
     // has errors
     1f32 == ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     TWO == ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     TWO != ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     ONE + ONE == TWO;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     let x = 1;
     x as f32 == ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     let v = 0.9;
     v == ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
     v != ONE;
     //~^ ERROR: strict comparison of `f32` or `f64` constant
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
     // no errors, lower than or greater than comparisons
     v < ONE;
@@ -70,5 +63,4 @@ fn main() {
     // has errors
     NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
     //~^ ERROR: strict comparison of `f32` or `f64` constant arrays
-    //~| NOTE: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 }
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.stderr b/src/tools/clippy/tests/ui/float_cmp_const.stderr
index bffd2acc2e0..4f88746e958 100644
--- a/src/tools/clippy/tests/ui/float_cmp_const.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp_const.stderr
@@ -4,65 +4,50 @@ error: strict comparison of `f32` or `f64` constant
 LL |     1f32 == ONE;
    |     ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin`
    |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
    = note: `-D clippy::float-cmp-const` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:19:5
+  --> tests/ui/float_cmp_const.rs:18:5
    |
 LL |     TWO == ONE;
    |     ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:22:5
+  --> tests/ui/float_cmp_const.rs:20:5
    |
 LL |     TWO != ONE;
    |     ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:25:5
+  --> tests/ui/float_cmp_const.rs:22:5
    |
 LL |     ONE + ONE == TWO;
    |     ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:29:5
+  --> tests/ui/float_cmp_const.rs:25:5
    |
 LL |     x as f32 == ONE;
    |     ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:34:5
+  --> tests/ui/float_cmp_const.rs:29:5
    |
 LL |     v == ONE;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:37:5
+  --> tests/ui/float_cmp_const.rs:31:5
    |
 LL |     v != ONE;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin`
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` constant arrays
-  --> tests/ui/float_cmp_const.rs:71:5
+  --> tests/ui/float_cmp_const.rs:64:5
    |
 LL |     NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/numbered_fields.fixed b/src/tools/clippy/tests/ui/init_numbered_fields.fixed
index 108520eed38..dca4e8da4d2 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.fixed
+++ b/src/tools/clippy/tests/ui/init_numbered_fields.fixed
@@ -39,4 +39,13 @@ fn main() {
     struct TupleStructVec(Vec<usize>);
 
     let _ = TupleStructVec(vec![0, 1, 2, 3]);
+
+    {
+        struct S(i32, i32);
+        let mut iter = [1i32, 1i32].into_iter();
+        let _ = S {
+            1: iter.next().unwrap(),
+            0: iter.next().unwrap(),
+        };
+    }
 }
diff --git a/src/tools/clippy/tests/ui/numbered_fields.rs b/src/tools/clippy/tests/ui/init_numbered_fields.rs
index c718661a682..8cb34705b4f 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.rs
+++ b/src/tools/clippy/tests/ui/init_numbered_fields.rs
@@ -47,4 +47,13 @@ fn main() {
     struct TupleStructVec(Vec<usize>);
 
     let _ = TupleStructVec { 0: vec![0, 1, 2, 3] };
+
+    {
+        struct S(i32, i32);
+        let mut iter = [1i32, 1i32].into_iter();
+        let _ = S {
+            1: iter.next().unwrap(),
+            0: iter.next().unwrap(),
+        };
+    }
 }
diff --git a/src/tools/clippy/tests/ui/numbered_fields.stderr b/src/tools/clippy/tests/ui/init_numbered_fields.stderr
index 9d3f59cd376..f176e0c2ff3 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.stderr
+++ b/src/tools/clippy/tests/ui/init_numbered_fields.stderr
@@ -1,5 +1,5 @@
 error: used a field initializer for a tuple struct
-  --> tests/ui/numbered_fields.rs:17:13
+  --> tests/ui/init_numbered_fields.rs:17:13
    |
 LL |       let _ = TupleStruct {
    |  _____________^
@@ -7,13 +7,13 @@ LL | |         0: 1u32,
 LL | |         1: 42,
 LL | |         2: 23u8,
 LL | |     };
-   | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)`
+   | |_____^ help: use tuple initialization: `TupleStruct(1u32, 42, 23u8)`
    |
    = note: `-D clippy::init-numbered-fields` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]`
 
 error: used a field initializer for a tuple struct
-  --> tests/ui/numbered_fields.rs:24:13
+  --> tests/ui/init_numbered_fields.rs:24:13
    |
 LL |       let _ = TupleStruct {
    |  _____________^
@@ -21,13 +21,13 @@ LL | |         0: 1u32,
 LL | |         2: 2u8,
 LL | |         1: 3u32,
 LL | |     };
-   | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)`
+   | |_____^ help: use tuple initialization: `TupleStruct(1u32, 3u32, 2u8)`
 
 error: used a field initializer for a tuple struct
-  --> tests/ui/numbered_fields.rs:49:13
+  --> tests/ui/init_numbered_fields.rs:49:13
    |
 LL |     let _ = TupleStructVec { 0: vec![0, 1, 2, 3] };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `TupleStructVec(vec![0, 1, 2, 3])`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use tuple initialization: `TupleStructVec(vec![0, 1, 2, 3])`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
index c8b9076041a..109259d6975 100644
--- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
@@ -185,3 +185,42 @@ pub mod issue11635 {
         }
     }
 }
+
+pub mod issue12964 {
+    pub struct MyIter<'a, T: 'a> {
+        iter: std::slice::Iter<'a, T>,
+    }
+
+    impl<'a, T> Iterator for MyIter<'a, T> {
+        type Item = &'a T;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            self.iter.next()
+        }
+    }
+
+    pub struct MyContainer<T> {
+        inner: Vec<T>,
+    }
+
+    impl<T> MyContainer<T> {}
+
+    impl<T> MyContainer<T> {
+        #[must_use]
+        pub fn iter(&self) -> MyIter<'_, T> {
+            <&Self as IntoIterator>::into_iter(self)
+        }
+    }
+
+    impl<'a, T> IntoIterator for &'a MyContainer<T> {
+        type Item = &'a T;
+
+        type IntoIter = MyIter<'a, T>;
+
+        fn into_iter(self) -> Self::IntoIter {
+            Self::IntoIter {
+                iter: self.inner.as_slice().iter(),
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/iter_next_loop.rs b/src/tools/clippy/tests/ui/iter_next_loop.rs
index 548b799de44..d425f4da0e8 100644
--- a/src/tools/clippy/tests/ui/iter_next_loop.rs
+++ b/src/tools/clippy/tests/ui/iter_next_loop.rs
@@ -3,7 +3,7 @@
 
 fn main() {
     let x = [1, 2, 3, 4];
-    for _ in vec.iter().next() {}
+    for _ in x.iter().next() {}
 
     struct Unrelated(&'static [u8]);
     impl Unrelated {
diff --git a/src/tools/clippy/tests/ui/iter_next_loop.stderr b/src/tools/clippy/tests/ui/iter_next_loop.stderr
index 85c23f4e709..acc55031c3b 100644
--- a/src/tools/clippy/tests/ui/iter_next_loop.stderr
+++ b/src/tools/clippy/tests/ui/iter_next_loop.stderr
@@ -1,9 +1,11 @@
-error[E0423]: expected value, found macro `vec`
+error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
   --> tests/ui/iter_next_loop.rs:6:14
    |
-LL |     for _ in vec.iter().next() {}
-   |              ^^^ not a value
+LL |     for _ in x.iter().next() {}
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iter-next-loop` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0423`.
diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr
index 8548c0cd294..0559b3bd661 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.stderr
+++ b/src/tools/clippy/tests/ui/manual_inspect.stderr
@@ -1,4 +1,4 @@
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:5:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -12,7 +12,7 @@ LL ~     let _ = Some(0).inspect(|&x| {
 LL ~         println!("{}", x);
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:10:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -24,7 +24,7 @@ LL ~     let _ = Some(0).inspect(|&x| {
 LL ~         println!("{x}");
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:15:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -36,7 +36,7 @@ LL ~     let _ = Some(0).inspect(|&x| {
 LL ~         println!("{}", x * 5 + 1);
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:20:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -50,7 +50,7 @@ LL |             panic!();
 LL ~         }
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:27:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -65,7 +65,7 @@ LL |             panic!();
 LL ~         }
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:78:41
    |
 LL |     let _ = Some((String::new(), 0u32)).map(|x| {
@@ -80,7 +80,7 @@ LL |             panic!();
 LL ~         }
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:104:33
    |
 LL |     let _ = Some(String::new()).map(|x| {
@@ -98,7 +98,7 @@ LL |         }
 LL ~         println!("test");
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:115:21
    |
 LL |     let _ = Some(0).map(|x| {
@@ -113,7 +113,7 @@ LL |             panic!();
 LL ~         }
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:130:46
    |
 LL |         let _ = Some(Cell2(Cell::new(0u32))).map(|x| {
@@ -125,7 +125,7 @@ LL ~         let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| {
 LL ~             x.0.set(1);
    |
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:146:34
    |
 LL |     let _: Result<_, ()> = Ok(0).map(|x| {
@@ -137,7 +137,7 @@ LL ~     let _: Result<_, ()> = Ok(0).inspect(|&x| {
 LL ~         println!("{}", x);
    |
 
-error: 
+error: using `map_err` over `inspect_err`
   --> tests/ui/manual_inspect.rs:151:35
    |
 LL |     let _: Result<(), _> = Err(0).map_err(|x| {
@@ -166,7 +166,7 @@ LL | |         .count();
    = note: `-D clippy::suspicious-map` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]`
 
-error: 
+error: using `map` over `inspect`
   --> tests/ui/manual_inspect.rs:158:10
    |
 LL |         .map(|x| {
diff --git a/src/tools/clippy/tests/ui/manual_rotate.fixed b/src/tools/clippy/tests/ui/manual_rotate.fixed
new file mode 100644
index 00000000000..5d33838a318
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_rotate.fixed
@@ -0,0 +1,31 @@
+#![warn(clippy::manual_rotate)]
+#![allow(unused)]
+fn main() {
+    let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64);
+    let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64);
+    let a_u32 = 1u32;
+    // True positives
+    let y_u8 = x_u8.rotate_right(3);
+    let y_u16 = x_u16.rotate_right(7);
+    let y_u32 = x_u32.rotate_right(8);
+    let y_u64 = x_u64.rotate_right(9);
+    let y_i8 = x_i8.rotate_right(3);
+    let y_i16 = x_i16.rotate_right(7);
+    let y_i32 = x_i32.rotate_right(8);
+    let y_i64 = x_i64.rotate_right(9);
+    // Plus also works instead of |
+    let y_u32_plus = x_u32.rotate_right(8);
+    // Complex expression
+    let y_u32_complex = (x_u32 | 3256).rotate_right(8);
+    let y_u64_as = (x_u32 as u64).rotate_right(8);
+
+    // False positives - can't be replaced with a rotation
+    let y_u8_false = (x_u8 >> 6) | (x_u8 << 3);
+    let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24);
+    let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55);
+    // Variable mismatch
+    let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24);
+    // Has side effects and therefore should not be matched
+    let mut l = vec![12_u8, 34];
+    let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5);
+}
diff --git a/src/tools/clippy/tests/ui/manual_rotate.rs b/src/tools/clippy/tests/ui/manual_rotate.rs
new file mode 100644
index 00000000000..5377491fb1a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_rotate.rs
@@ -0,0 +1,31 @@
+#![warn(clippy::manual_rotate)]
+#![allow(unused)]
+fn main() {
+    let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64);
+    let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64);
+    let a_u32 = 1u32;
+    // True positives
+    let y_u8 = (x_u8 >> 3) | (x_u8 << 5);
+    let y_u16 = (x_u16 >> 7) | (x_u16 << 9);
+    let y_u32 = (x_u32 >> 8) | (x_u32 << 24);
+    let y_u64 = (x_u64 >> 9) | (x_u64 << 55);
+    let y_i8 = (x_i8 >> 3) | (x_i8 << 5);
+    let y_i16 = (x_i16 >> 7) | (x_i16 << 9);
+    let y_i32 = (x_i32 >> 8) | (x_i32 << 24);
+    let y_i64 = (x_i64 >> 9) | (x_i64 << 55);
+    // Plus also works instead of |
+    let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24);
+    // Complex expression
+    let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24);
+    let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56);
+
+    // False positives - can't be replaced with a rotation
+    let y_u8_false = (x_u8 >> 6) | (x_u8 << 3);
+    let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24);
+    let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55);
+    // Variable mismatch
+    let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24);
+    // Has side effects and therefore should not be matched
+    let mut l = vec![12_u8, 34];
+    let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5);
+}
diff --git a/src/tools/clippy/tests/ui/manual_rotate.stderr b/src/tools/clippy/tests/ui/manual_rotate.stderr
new file mode 100644
index 00000000000..52da0861f70
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_rotate.stderr
@@ -0,0 +1,71 @@
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:8:16
+   |
+LL |     let y_u8 = (x_u8 >> 3) | (x_u8 << 5);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u8.rotate_right(3)`
+   |
+   = note: `-D clippy::manual-rotate` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_rotate)]`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:9:17
+   |
+LL |     let y_u16 = (x_u16 >> 7) | (x_u16 << 9);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u16.rotate_right(7)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:10:17
+   |
+LL |     let y_u32 = (x_u32 >> 8) | (x_u32 << 24);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:11:17
+   |
+LL |     let y_u64 = (x_u64 >> 9) | (x_u64 << 55);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u64.rotate_right(9)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:12:16
+   |
+LL |     let y_i8 = (x_i8 >> 3) | (x_i8 << 5);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i8.rotate_right(3)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:13:17
+   |
+LL |     let y_i16 = (x_i16 >> 7) | (x_i16 << 9);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i16.rotate_right(7)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:14:17
+   |
+LL |     let y_i32 = (x_i32 >> 8) | (x_i32 << 24);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i32.rotate_right(8)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:15:17
+   |
+LL |     let y_i64 = (x_i64 >> 9) | (x_i64 << 55);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i64.rotate_right(9)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:17:22
+   |
+LL |     let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:19:25
+   |
+LL |     let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 | 3256).rotate_right(8)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:20:20
+   |
+LL |     let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 as u64).rotate_right(8)`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index 2750e0cdf3f..2c6e1e92da0 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -7,6 +7,7 @@
 
 #![warn(clippy::missing_const_for_fn)]
 #![feature(start)]
+#![feature(type_alias_impl_trait)]
 
 extern crate helper;
 extern crate proc_macros;
@@ -180,4 +181,21 @@ mod msrv {
             unsafe { *self.1 as usize }
         }
     }
+
+    #[clippy::msrv = "1.61"]
+    extern "C" fn c() {}
+}
+
+mod with_extern {
+    extern "C-unwind" fn c_unwind() {}
+    extern "system" fn system() {}
+    extern "system-unwind" fn system_unwind() {}
+}
+
+mod with_ty_alias {
+    type Foo = impl std::fmt::Debug;
+
+    fn foo(_: Foo) {
+        let _: Foo = 1;
+    }
 }
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
index f8fc935f367..dbd739eee13 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
@@ -143,6 +143,21 @@ mod msrv {
         let bar = Bar { val: 1 };
         let _ = unsafe { bar.val };
     }
+
+    #[clippy::msrv = "1.62"]
+    mod with_extern {
+        const extern "C" fn c() {}
+        //~^ ERROR: this could be a `const fn`
+
+        #[rustfmt::skip]
+        const extern fn implicit_c() {}
+        //~^ ERROR: this could be a `const fn`
+
+        // any item functions in extern block won't trigger this lint
+        extern "C" {
+            fn c_in_block();
+        }
+    }
 }
 
 mod issue12677 {
@@ -174,3 +189,18 @@ mod issue12677 {
         }
     }
 }
+
+mod with_ty_alias {
+    trait FooTrait {
+        type Foo: std::fmt::Debug;
+        fn bar(_: Self::Foo) {}
+    }
+    impl FooTrait for () {
+        type Foo = i32;
+    }
+    // NOTE: When checking the type of a function param, make sure it is not an alias with
+    // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type
+    // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated
+    // in this test.
+    const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 5e4e2c58e5a..4ac56f4c803 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -143,6 +143,21 @@ mod msrv {
         let bar = Bar { val: 1 };
         let _ = unsafe { bar.val };
     }
+
+    #[clippy::msrv = "1.62"]
+    mod with_extern {
+        extern "C" fn c() {}
+        //~^ ERROR: this could be a `const fn`
+
+        #[rustfmt::skip]
+        extern fn implicit_c() {}
+        //~^ ERROR: this could be a `const fn`
+
+        // any item functions in extern block won't trigger this lint
+        extern "C" {
+            fn c_in_block();
+        }
+    }
 }
 
 mod issue12677 {
@@ -174,3 +189,18 @@ mod issue12677 {
         }
     }
 }
+
+mod with_ty_alias {
+    trait FooTrait {
+        type Foo: std::fmt::Debug;
+        fn bar(_: Self::Foo) {}
+    }
+    impl FooTrait for () {
+        type Foo = i32;
+    }
+    // NOTE: When checking the type of a function param, make sure it is not an alias with
+    // `AliasTyKind::Projection` before calling `TyCtxt::type_of` to find out what the actual type
+    // is. Because the associate ty could have no default, therefore would cause ICE, as demostrated
+    // in this test.
+    fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 8302b074127..fb4db703103 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -211,7 +211,29 @@ LL |     const fn union_access_can_be_const() {
    |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:155:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:149:9
+   |
+LL |         extern "C" fn c() {}
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL |         const extern "C" fn c() {}
+   |         +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9
+   |
+LL |         extern fn implicit_c() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL |         const extern fn implicit_c() {}
+   |         +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9
    |
 LL | /         pub fn new(strings: Vec<String>) -> Self {
 LL | |             Self { strings }
@@ -224,7 +246,7 @@ LL |         pub const fn new(strings: Vec<String>) -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:160:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9
    |
 LL | /         pub fn empty() -> Self {
 LL | |             Self { strings: Vec::new() }
@@ -237,7 +259,7 @@ LL |         pub const fn empty() -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9
    |
 LL | /         pub fn new(text: String) -> Self {
 LL | |             let vec = Vec::new();
@@ -250,5 +272,16 @@ help: make the function `const`
 LL |         pub const fn new(text: String) -> Self {
    |             +++++
 
-error: aborting due to 18 previous errors
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5
+   |
+LL |     fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL |     const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
+   |     +++++
+
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed
new file mode 100644
index 00000000000..c103db536ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed
@@ -0,0 +1,14 @@
+#![warn(clippy::missing_const_for_fn)]
+#![allow(unsupported_calling_conventions)]
+#![feature(const_extern_fn)]
+
+const extern "C-unwind" fn c_unwind() {}
+//~^ ERROR: this could be a `const fn`
+const extern "system" fn system() {}
+//~^ ERROR: this could be a `const fn`
+const extern "system-unwind" fn system_unwind() {}
+//~^ ERROR: this could be a `const fn`
+pub const extern "stdcall" fn std_call() {}
+//~^ ERROR: this could be a `const fn`
+pub const extern "stdcall-unwind" fn std_call_unwind() {}
+//~^ ERROR: this could be a `const fn`
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs
new file mode 100644
index 00000000000..0f7020ae559
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs
@@ -0,0 +1,14 @@
+#![warn(clippy::missing_const_for_fn)]
+#![allow(unsupported_calling_conventions)]
+#![feature(const_extern_fn)]
+
+extern "C-unwind" fn c_unwind() {}
+//~^ ERROR: this could be a `const fn`
+extern "system" fn system() {}
+//~^ ERROR: this could be a `const fn`
+extern "system-unwind" fn system_unwind() {}
+//~^ ERROR: this could be a `const fn`
+pub extern "stdcall" fn std_call() {}
+//~^ ERROR: this could be a `const fn`
+pub extern "stdcall-unwind" fn std_call_unwind() {}
+//~^ ERROR: this could be a `const fn`
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr
new file mode 100644
index 00000000000..036094a367b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr
@@ -0,0 +1,59 @@
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:5:1
+   |
+LL | extern "C-unwind" fn c_unwind() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]`
+help: make the function `const`
+   |
+LL | const extern "C-unwind" fn c_unwind() {}
+   | +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:7:1
+   |
+LL | extern "system" fn system() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | const extern "system" fn system() {}
+   | +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:9:1
+   |
+LL | extern "system-unwind" fn system_unwind() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | const extern "system-unwind" fn system_unwind() {}
+   | +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:11:1
+   |
+LL | pub extern "stdcall" fn std_call() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | pub const extern "stdcall" fn std_call() {}
+   |     +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:13:1
+   |
+LL | pub extern "stdcall-unwind" fn std_call_unwind() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | pub const extern "stdcall-unwind" fn std_call_unwind() {}
+   |     +++++
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed
index 4c9bd0bd863..90b31b9b5d2 100644
--- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed
@@ -1,4 +1,4 @@
-#![warn(clippy::thread_local_initializer_can_be_made_const)]
+#![warn(clippy::missing_const_for_thread_local)]
 
 use std::cell::{Cell, RefCell};
 
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs
index eb336f0dd19..f97e4848fd7 100644
--- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::thread_local_initializer_can_be_made_const)]
+#![warn(clippy::missing_const_for_thread_local)]
 
 use std::cell::{Cell, RefCell};
 
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr
index b4f8bd822b0..c143a37454f 100644
--- a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr
@@ -1,38 +1,38 @@
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:8:41
+  --> tests/ui/missing_const_for_thread_local.rs:8:41
    |
 LL |         static BUF_1: RefCell<String> = RefCell::new(String::new());
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
    |
-   = note: `-D clippy::thread-local-initializer-can-be-made-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::thread_local_initializer_can_be_made_const)]`
+   = note: `-D clippy::missing-const-for-thread-local` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_thread_local)]`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:18:29
+  --> tests/ui/missing_const_for_thread_local.rs:18:29
    |
 LL |         static SIMPLE:i32 = 1;
    |                             ^ help: replace with: `const { 1 }`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:24:59
+  --> tests/ui/missing_const_for_thread_local.rs:24:59
    |
 LL |         static BUF_3_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:26:59
+  --> tests/ui/missing_const_for_thread_local.rs:26:59
    |
 LL |         static BUF_4_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:32:31
+  --> tests/ui/missing_const_for_thread_local.rs:32:31
    |
 LL |         static PEEL_ME: i32 = { 1 };
    |                               ^^^^^ help: replace with: `const { 1 }`
 
 error: initializer for `thread_local` value can be made `const`
-  --> tests/ui/thread_local_initializer_can_be_made_const.rs:34:36
+  --> tests/ui/missing_const_for_thread_local.rs:34:36
    |
 LL |         static PEEL_ME_MANY: i32 = { let x = 1; x * x };
    |                                    ^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { { let x = 1; x * x } }`
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
index eee62122fdf..162ec82aede 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -232,43 +232,48 @@ async fn async_vec2(b: &mut Vec<bool>) {
 }
 fn non_mut(n: &str) {}
 //Should warn
-pub async fn call_in_closure1(n: &mut str) {
+async fn call_in_closure1(n: &mut str) {
     (|| non_mut(n))()
 }
 fn str_mut(str: &mut String) -> bool {
     str.pop().is_some()
 }
 //Should not warn
-pub async fn call_in_closure2(str: &mut String) {
+async fn call_in_closure2(str: &mut String) {
     (|| str_mut(str))();
 }
 
 // Should not warn.
-pub async fn closure(n: &mut usize) -> impl '_ + FnMut() {
+async fn closure(n: &mut usize) -> impl '_ + FnMut() {
     || {
         *n += 1;
     }
 }
 
 // Should warn.
-pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
+fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     || *n + 1
 }
 
 // Should not warn.
-pub async fn closure3(n: &mut usize) {
+async fn closure3(n: &mut usize) {
     (|| *n += 1)();
 }
 
 // Should warn.
-pub async fn closure4(n: &mut usize) {
+async fn closure4(n: &mut usize) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     (|| {
         let _x = *n + 1;
     })();
 }
 
+// Should not warn: pub
+pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+    *x += *b + s.len() as u32;
+}
+
 // Should not warn.
 async fn _f(v: &mut Vec<()>) {
     let x = || v.pop();
@@ -365,4 +370,5 @@ fn main() {
     used_as_path;
     let _: fn(&mut u32) = passed_as_local;
     let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 };
+    pub_foo(&mut v, &0, &mut u);
 }
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
index 51e3ba37ded..f462fa9099e 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
@@ -108,109 +108,103 @@ LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
    |                          ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:235:34
+  --> tests/ui/needless_pass_by_ref_mut.rs:235:30
    |
-LL | pub async fn call_in_closure1(n: &mut str) {
-   |                                  ^^^^^^^^ help: consider changing to: `&str`
-   |
-   = warning: changing this function will impact semver compatibility
+LL | async fn call_in_closure1(n: &mut str) {
+   |                              ^^^^^^^^ help: consider changing to: `&str`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:254:20
-   |
-LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
-   |                    ^^^^^^^^^^ help: consider changing to: `&usize`
+  --> tests/ui/needless_pass_by_ref_mut.rs:254:16
    |
-   = warning: changing this function will impact semver compatibility
+LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
+   |                ^^^^^^^^^^ help: consider changing to: `&usize`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:265:26
-   |
-LL | pub async fn closure4(n: &mut usize) {
-   |                          ^^^^^^^^^^ help: consider changing to: `&usize`
+  --> tests/ui/needless_pass_by_ref_mut.rs:265:22
    |
-   = warning: changing this function will impact semver compatibility
+LL | async fn closure4(n: &mut usize) {
+   |                      ^^^^^^^^^^ help: consider changing to: `&usize`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:314:12
+  --> tests/ui/needless_pass_by_ref_mut.rs:319:12
    |
 LL |     fn bar(&mut self) {}
    |            ^^^^^^^^^ help: consider changing to: `&self`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:316:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:321:18
    |
 LL |     async fn foo(&mut self, u: &mut i32, v: &mut u32) {
    |                  ^^^^^^^^^ help: consider changing to: `&self`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:316:45
+  --> tests/ui/needless_pass_by_ref_mut.rs:321:45
    |
 LL |     async fn foo(&mut self, u: &mut i32, v: &mut u32) {
    |                                             ^^^^^^^^ help: consider changing to: `&u32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:324:46
+  --> tests/ui/needless_pass_by_ref_mut.rs:329:46
    |
 LL |     async fn foo2(&mut self, u: &mut i32, v: &mut u32) {
    |                                              ^^^^^^^^ help: consider changing to: `&u32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:340:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:345:18
    |
 LL | fn _empty_tup(x: &mut (())) {}
    |                  ^^^^^^^^^ help: consider changing to: `&()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:341:19
+  --> tests/ui/needless_pass_by_ref_mut.rs:346:19
    |
 LL | fn _single_tup(x: &mut ((i32,))) {}
    |                   ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:342:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:347:18
    |
 LL | fn _multi_tup(x: &mut ((i32, u32))) {}
    |                  ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:343:11
+  --> tests/ui/needless_pass_by_ref_mut.rs:348:11
    |
 LL | fn _fn(x: &mut (fn())) {}
    |           ^^^^^^^^^^^ help: consider changing to: `&fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:345:23
+  --> tests/ui/needless_pass_by_ref_mut.rs:350:23
    |
 LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
    |                       ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:346:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:351:20
    |
 LL | fn _extern_c_fn(x: &mut extern "C" fn()) {}
    |                    ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:347:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:352:18
    |
 LL | fn _unsafe_fn(x: &mut unsafe fn()) {}
    |                  ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:348:25
+  --> tests/ui/needless_pass_by_ref_mut.rs:353:25
    |
 LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:349:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:354:20
    |
 LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:350:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:355:20
    |
 LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)`
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed
index 3c2576213cd..f26b39ea6a1 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed
@@ -5,7 +5,7 @@
 #![allow(clippy::redundant_closure_call)]
 #![warn(clippy::needless_pass_by_ref_mut)]
 
-pub async fn inner_async3(x: &i32, y: &mut u32) {
+async fn inner_async3(x: &i32, y: &mut u32) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     async {
         *y += 1;
@@ -13,7 +13,7 @@ pub async fn inner_async3(x: &i32, y: &mut u32) {
     .await;
 }
 
-pub async fn inner_async4(u: &mut i32, v: &u32) {
+async fn inner_async4(u: &mut i32, v: &u32) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     async {
         *u += 1;
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs
index 34b0b564deb..4220215b1fe 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs
@@ -5,7 +5,7 @@
 #![allow(clippy::redundant_closure_call)]
 #![warn(clippy::needless_pass_by_ref_mut)]
 
-pub async fn inner_async3(x: &mut i32, y: &mut u32) {
+async fn inner_async3(x: &mut i32, y: &mut u32) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     async {
         *y += 1;
@@ -13,7 +13,7 @@ pub async fn inner_async3(x: &mut i32, y: &mut u32) {
     .await;
 }
 
-pub async fn inner_async4(u: &mut i32, v: &mut u32) {
+async fn inner_async4(u: &mut i32, v: &mut u32) {
     //~^ ERROR: this argument is a mutable reference, but not used mutably
     async {
         *u += 1;
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr
index c8753603225..1c0136cf5d5 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr
@@ -1,20 +1,17 @@
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut2.rs:8:30
+  --> tests/ui/needless_pass_by_ref_mut2.rs:8:26
    |
-LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) {
-   |                              ^^^^^^^^ help: consider changing to: `&i32`
+LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
+   |                          ^^^^^^^^ help: consider changing to: `&i32`
    |
-   = warning: changing this function will impact semver compatibility
    = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut2.rs:16:43
+  --> tests/ui/needless_pass_by_ref_mut2.rs:16:39
    |
-LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) {
-   |                                           ^^^^^^^^ help: consider changing to: `&u32`
-   |
-   = warning: changing this function will impact semver compatibility
+LL | async fn inner_async4(u: &mut i32, v: &mut u32) {
+   |                                       ^^^^^^^^ help: consider changing to: `&u32`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index 853f685f04c..fc4129e1db8 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -228,12 +228,41 @@ fn needless_return_macro() -> String {
     format!("Hello {}", "world!")
 }
 
-fn issue_9361() -> i32 {
-    let n = 1;
-    #[allow(clippy::arithmetic_side_effects)]
+fn issue_9361(n: i32) -> i32 {
+    #[expect(clippy::arithmetic_side_effects)]
     return n + n;
 }
 
+mod issue_12998 {
+    fn expect_lint() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::needless_return)]
+        return x;
+    }
+
+    fn expect_group() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::style)]
+        return x;
+    }
+
+    fn expect_all() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::all)]
+        return x;
+    }
+
+    fn expect_warnings() -> i32 {
+        let x = 1;
+
+        #[expect(warnings)]
+        return x;
+    }
+}
+
 fn issue8336(x: i32) -> bool {
     if x > 0 {
         println!("something");
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index e9c1e0e8ae8..61c7a02008f 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -236,12 +236,41 @@ fn needless_return_macro() -> String {
     return format!("Hello {}", "world!");
 }
 
-fn issue_9361() -> i32 {
-    let n = 1;
-    #[allow(clippy::arithmetic_side_effects)]
+fn issue_9361(n: i32) -> i32 {
+    #[expect(clippy::arithmetic_side_effects)]
     return n + n;
 }
 
+mod issue_12998 {
+    fn expect_lint() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::needless_return)]
+        return x;
+    }
+
+    fn expect_group() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::style)]
+        return x;
+    }
+
+    fn expect_all() -> i32 {
+        let x = 1;
+
+        #[expect(clippy::all)]
+        return x;
+    }
+
+    fn expect_warnings() -> i32 {
+        let x = 1;
+
+        #[expect(warnings)]
+        return x;
+    }
+}
+
 fn issue8336(x: i32) -> bool {
     if x > 0 {
         println!("something");
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 6c891fe7ad3..ea9c230eafd 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -483,7 +483,7 @@ LL +     format!("Hello {}", "world!")
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:248:9
+  --> tests/ui/needless_return.rs:277:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -497,7 +497,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:250:9
+  --> tests/ui/needless_return.rs:279:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -509,7 +509,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:257:13
+  --> tests/ui/needless_return.rs:286:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
@@ -524,7 +524,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:260:13
+  --> tests/ui/needless_return.rs:289:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
@@ -537,7 +537,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:268:9
+  --> tests/ui/needless_return.rs:297:9
    |
 LL |         return 0;
    |         ^^^^^^^^
@@ -549,7 +549,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:275:13
+  --> tests/ui/needless_return.rs:304:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -564,7 +564,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:277:13
+  --> tests/ui/needless_return.rs:306:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -577,7 +577,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:284:20
+  --> tests/ui/needless_return.rs:313:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -594,7 +594,7 @@ LL +         let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:291:20
+  --> tests/ui/needless_return.rs:320:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
@@ -606,7 +606,7 @@ LL +         let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:303:9
+  --> tests/ui/needless_return.rs:332:9
    |
 LL |         return Ok(format!("ok!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -618,7 +618,7 @@ LL +         Ok(format!("ok!"))
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:305:9
+  --> tests/ui/needless_return.rs:334:9
    |
 LL |         return Err(format!("err!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -630,7 +630,7 @@ LL +         Err(format!("err!"))
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:311:9
+  --> tests/ui/needless_return.rs:340:9
    |
 LL |         return if true { 1 } else { 2 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -642,7 +642,7 @@ LL +         if true { 1 } else { 2 }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:315:9
+  --> tests/ui/needless_return.rs:344:9
    |
 LL |         return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -654,7 +654,7 @@ LL +         (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:336:5
+  --> tests/ui/needless_return.rs:365:5
    |
 LL |     return { "a".to_string() } + "b" + { "c" };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.rs b/src/tools/clippy/tests/ui/overflow_check_conditional.rs
deleted file mode 100644
index a70bb3bc47b..00000000000
--- a/src/tools/clippy/tests/ui/overflow_check_conditional.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#![warn(clippy::overflow_check_conditional)]
-#![allow(clippy::needless_if)]
-
-fn test(a: u32, b: u32, c: u32) {
-    if a + b < a {}
-    //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust
-    //~| NOTE: `-D clippy::overflow-check-conditional` implied by `-D warnings`
-    if a > a + b {}
-    //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust
-    if a + b < b {}
-    //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust
-    if b > a + b {}
-    //~^ ERROR: you are trying to use classic C overflow conditions that will fail in Rust
-    if a - b > b {}
-    //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus
-    if b < a - b {}
-    //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus
-    if a - b > a {}
-    //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus
-    if a < a - b {}
-    //~^ ERROR: you are trying to use classic C underflow conditions that will fail in Rus
-    if a + b < c {}
-    if c > a + b {}
-    if a - b < c {}
-    if c > a - b {}
-    let i = 1.1;
-    let j = 2.2;
-    if i + j < i {}
-    if i - j < i {}
-    if i > i + j {}
-    if i - j < i {}
-}
-
-fn main() {
-    test(1, 2, 3)
-}
diff --git a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr b/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
deleted file mode 100644
index c14532bad5a..00000000000
--- a/src/tools/clippy/tests/ui/overflow_check_conditional.stderr
+++ /dev/null
@@ -1,53 +0,0 @@
-error: you are trying to use classic C overflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:5:8
-   |
-LL |     if a + b < a {}
-   |        ^^^^^^^^^
-   |
-   = note: `-D clippy::overflow-check-conditional` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::overflow_check_conditional)]`
-
-error: you are trying to use classic C overflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:8:8
-   |
-LL |     if a > a + b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C overflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:10:8
-   |
-LL |     if a + b < b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C overflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:12:8
-   |
-LL |     if b > a + b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C underflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:14:8
-   |
-LL |     if a - b > b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C underflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:16:8
-   |
-LL |     if b < a - b {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C underflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:18:8
-   |
-LL |     if a - b > a {}
-   |        ^^^^^^^^^
-
-error: you are trying to use classic C underflow conditions that will fail in Rust
-  --> tests/ui/overflow_check_conditional.rs:20:8
-   |
-LL |     if a < a - b {}
-   |        ^^^^^^^^^
-
-error: aborting due to 8 previous errors
-
diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.rs b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs
new file mode 100644
index 00000000000..dc2ddeada1e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs
@@ -0,0 +1,27 @@
+#![warn(clippy::panicking_overflow_checks)]
+#![allow(clippy::needless_if)]
+
+fn test(a: u32, b: u32, c: u32) {
+    if a + b < a {} //~ panicking_overflow_checks
+    if a > a + b {} //~ panicking_overflow_checks
+    if a + b < b {} //~ panicking_overflow_checks
+    if b > a + b {} //~ panicking_overflow_checks
+    if a - b > b {}
+    if b < a - b {}
+    if a - b > a {} //~ panicking_overflow_checks
+    if a < a - b {} //~ panicking_overflow_checks
+    if a + b < c {}
+    if c > a + b {}
+    if a - b < c {}
+    if c > a - b {}
+    let i = 1.1;
+    let j = 2.2;
+    if i + j < i {}
+    if i - j < i {}
+    if i > i + j {}
+    if i - j < i {}
+}
+
+fn main() {
+    test(1, 2, 3)
+}
diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr b/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr
new file mode 100644
index 00000000000..1fae0457889
--- /dev/null
+++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr
@@ -0,0 +1,41 @@
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:5:8
+   |
+LL |     if a + b < a {}
+   |        ^^^^^^^^^
+   |
+   = note: `-D clippy::panicking-overflow-checks` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::panicking_overflow_checks)]`
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:6:8
+   |
+LL |     if a > a + b {}
+   |        ^^^^^^^^^
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:7:8
+   |
+LL |     if a + b < b {}
+   |        ^^^^^^^^^
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:8:8
+   |
+LL |     if b > a + b {}
+   |        ^^^^^^^^^
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:11:8
+   |
+LL |     if a - b > a {}
+   |        ^^^^^^^^^
+
+error: you are trying to use classic C overflow conditions that will fail in Rust
+  --> tests/ui/panicking_overflow_checks.rs:12:8
+   |
+LL |     if a < a - b {}
+   |        ^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
index e162f35baf5..18462620b0a 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
@@ -1,4 +1,4 @@
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:18:33
    |
 LL |         *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
@@ -7,37 +7,37 @@ LL |         *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i
    = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:27:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:28:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:33:17
    |
 LL |         let _ = *ptr_ptr as *const i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:46:25
    |
 LL |     let _: *const i32 = ptr as *const _;
    |                         ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:47:23
    |
 LL |     let _: *mut i32 = mut_ptr as _;
    |                       ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:50:21
    |
 LL |     let _ = inline!($ptr as *const i32);
@@ -45,157 +45,157 @@ LL |     let _ = inline!($ptr as *const i32);
    |
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:71:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:72:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:79:9
    |
 LL |         ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:83:9
    |
 LL |         std::ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:88:9
    |
 LL |         ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:92:9
    |
 LL |         core::ptr::null_mut() as *mut u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:97:9
    |
 LL |         ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:101:9
    |
 LL |         std::ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:106:9
    |
 LL |         ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:110:9
    |
 LL |         core::ptr::null() as *const u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:117:9
    |
 LL |         ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:121:9
    |
 LL |         std::ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:126:9
    |
 LL |         ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:130:9
    |
 LL |         core::ptr::null_mut() as *mut _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:135:9
    |
 LL |         ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:139:9
    |
 LL |         std::ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:144:9
    |
 LL |         ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:148:9
    |
 LL |         core::ptr::null() as *const _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:155:9
    |
 LL |         ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:159:9
    |
 LL |         std::ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:164:9
    |
 LL |         ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:168:9
    |
 LL |         core::ptr::null_mut() as _
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:173:9
    |
 LL |         ptr::null() as _
    |         ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:177:9
    |
 LL |         std::ptr::null() as _
    |         ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:182:9
    |
 LL |         ptr::null() as _
    |         ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()`
 
-error: `as` casting between raw pointers without changing its mutability
+error: `as` casting between raw pointers without changing their constness
   --> tests/ui/ptr_as_ptr.rs:186:9
    |
 LL |         core::ptr::null() as _
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 24d0f797542..d70c9f8d06c 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -24,9 +24,11 @@
 #![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
+#![allow(clippy::panicking_overflow_checks)]
 #![allow(clippy::needless_borrow)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
+#![allow(clippy::missing_const_for_thread_local)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
@@ -77,12 +79,14 @@
 #![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)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index be8da2fa1a3..8d0ac3c8f95 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -24,9 +24,11 @@
 #![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
+#![allow(clippy::panicking_overflow_checks)]
 #![allow(clippy::needless_borrow)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
+#![allow(clippy::missing_const_for_thread_local)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
@@ -77,12 +79,14 @@
 #![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)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 777ac20153d..d6637324a03 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:56:9
+  --> tests/ui/rename.rs:58:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,346 +8,358 @@ 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:57:9
+  --> tests/ui/rename.rs:59: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:58:9
+  --> tests/ui/rename.rs:60: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:59:9
+  --> tests/ui/rename.rs:61: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:60:9
+  --> tests/ui/rename.rs:62: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:61:9
+  --> tests/ui/rename.rs:63: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:62:9
+  --> tests/ui/rename.rs:64: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:63:9
+  --> tests/ui/rename.rs:65: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:64:9
+  --> tests/ui/rename.rs:66: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:65:9
+  --> tests/ui/rename.rs:67: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:66:9
+  --> tests/ui/rename.rs:68: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:67:9
+  --> tests/ui/rename.rs:69:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:68:9
+  --> tests/ui/rename.rs:70:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:69:9
+  --> tests/ui/rename.rs:71: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:70:9
+  --> tests/ui/rename.rs:72: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:71:9
+  --> tests/ui/rename.rs:73: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:72:9
+  --> tests/ui/rename.rs:74: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:73:9
+  --> tests/ui/rename.rs:75: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:74:9
+  --> tests/ui/rename.rs:76: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:75:9
+  --> tests/ui/rename.rs:77: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:76:9
+  --> tests/ui/rename.rs:78: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:77:9
+  --> tests/ui/rename.rs:79: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:78:9
+  --> tests/ui/rename.rs:80: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:79:9
+  --> tests/ui/rename.rs:81: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
+   |
+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:80:9
+  --> tests/ui/rename.rs:83: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:81:9
+  --> tests/ui/rename.rs:84: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:82:9
+  --> tests/ui/rename.rs:85: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:83:9
+  --> tests/ui/rename.rs:86: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:84:9
+  --> tests/ui/rename.rs:87: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:85:9
+  --> tests/ui/rename.rs:88: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
+   |
+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:86:9
+  --> tests/ui/rename.rs:90: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:87:9
+  --> tests/ui/rename.rs:91: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:88:9
+  --> tests/ui/rename.rs:92: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:89:9
+  --> tests/ui/rename.rs:93: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:90:9
+  --> tests/ui/rename.rs:94: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:91:9
+  --> tests/ui/rename.rs:95: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:92:9
+  --> tests/ui/rename.rs:96: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:93:9
+  --> tests/ui/rename.rs:97: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:94:9
+  --> tests/ui/rename.rs:98: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:95:9
+  --> tests/ui/rename.rs:99: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:96:9
+  --> tests/ui/rename.rs:100: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:97:9
+  --> tests/ui/rename.rs:101: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:98:9
+  --> tests/ui/rename.rs:102: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:99:9
+  --> tests/ui/rename.rs:103: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:100:9
+  --> tests/ui/rename.rs:104: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:101:9
+  --> tests/ui/rename.rs:105: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:102:9
+  --> tests/ui/rename.rs:106: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:103:9
+  --> tests/ui/rename.rs:107: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:104:9
+  --> tests/ui/rename.rs:108: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:105:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:106:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:107:9
+  --> tests/ui/rename.rs:111: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:108:9
+  --> tests/ui/rename.rs:112: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:109:9
+  --> tests/ui/rename.rs:113: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:110:9
+  --> tests/ui/rename.rs:114: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:111:9
+  --> tests/ui/rename.rs:115: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:112:9
+  --> tests/ui/rename.rs:116: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:113:9
+  --> tests/ui/rename.rs:117:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
-error: aborting due to 58 previous errors
+error: aborting due to 60 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
new file mode 100644
index 00000000000..8465007402a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/set_contains_or_insert.rs
@@ -0,0 +1,83 @@
+#![allow(unused)]
+#![allow(clippy::nonminimal_bool)]
+#![allow(clippy::needless_borrow)]
+#![warn(clippy::set_contains_or_insert)]
+
+use std::collections::HashSet;
+
+fn main() {
+    should_warn_cases();
+
+    should_not_warn_cases();
+}
+
+fn should_warn_cases() {
+    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);
+    }
+
+    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_not_warn_cases() {
+    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 simply_true() -> bool {
+    true
+}
diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
new file mode 100644
index 00000000000..507e20964fc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
@@ -0,0 +1,61 @@
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:18:13
+   |
+LL |     if !set.contains(&value) {
+   |             ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::set-contains-or-insert` implied by `-D warnings`
+   = 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
+   |
+LL |     if set.contains(&value) {
+   |            ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:28:13
+   |
+LL |     if !set.contains(&value) {
+   |             ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:32:14
+   |
+LL |     if !!set.contains(&value) {
+   |              ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:37:15
+   |
+LL |     if (&set).contains(&value) {
+   |               ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:42:13
+   |
+LL |     if !set.contains(borrow_value) {
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+LL |         set.insert(*borrow_value);
+   |             ^^^^^^^^^^^^^^^^^^^^^
+
+error: usage of `HashSet::insert` after `HashSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:47:20
+   |
+LL |     if !borrow_set.contains(&value) {
+   |                    ^^^^^^^^^^^^^^^^
+LL |         borrow_set.insert(value);
+   |                    ^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index 8ee15440ccf..0db6fbfb7be 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -801,4 +801,30 @@ fn should_not_trigger_lint_with_explicit_drop() {
     }
 }
 
+fn should_trigger_lint_in_if_let() {
+    let mutex = Mutex::new(vec![1]);
+
+    if let Some(val) = mutex.lock().unwrap().first().copied() {
+        //~^ ERROR: temporary with significant `Drop` in `if let` scrutinee will live until the
+        //~| NOTE: this might lead to deadlocks or other unexpected behavior
+        println!("{}", val);
+    }
+
+    // Should not trigger lint without the final `copied()`, because we actually hold a reference
+    // (i.e., the `val`) to the locked data.
+    if let Some(val) = mutex.lock().unwrap().first() {
+        println!("{}", val);
+    };
+}
+
+fn should_trigger_lint_in_while_let() {
+    let mutex = Mutex::new(vec![1]);
+
+    while let Some(val) = mutex.lock().unwrap().pop() {
+        //~^ ERROR: temporary with significant `Drop` in `while let` scrutinee will live until the
+        //~| NOTE: this might lead to deadlocks or other unexpected behavior
+        println!("{}", val);
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
index 4a483e79d8a..c0c93cd10c0 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
@@ -541,5 +541,32 @@ LL ~     let value = mutex.lock().unwrap()[0];
 LL ~     for val in [value, 2] {
    |
 
-error: aborting due to 27 previous errors
+error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression
+  --> tests/ui/significant_drop_in_scrutinee.rs:807:24
+   |
+LL |     if let Some(val) = mutex.lock().unwrap().first().copied() {
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     }
+   |      - temporary lives until here
+   |
+   = note: this might lead to deadlocks or other unexpected behavior
+help: try moving the temporary above the match
+   |
+LL ~     let value = mutex.lock().unwrap().first().copied();
+LL ~     if let Some(val) = value {
+   |
+
+error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression
+  --> tests/ui/significant_drop_in_scrutinee.rs:823:27
+   |
+LL |     while let Some(val) = mutex.lock().unwrap().pop() {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     }
+   |      - temporary lives until here
+   |
+   = note: this might lead to deadlocks or other unexpected behavior
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
index 11761c6c90e..006f123cbcd 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
@@ -43,7 +43,7 @@ fn get_number() -> i32 {
     0
 }
 
-fn get_usize() -> usize {
+const fn get_usize() -> usize {
     0
 }
 fn get_struct() -> Struct {
@@ -113,4 +113,16 @@ fn main() {
     'label: {
         break 'label
     };
+    let () = const {
+        [42, 55][get_usize()];
+    };
+}
+
+const _: () = {
+    [42, 55][get_usize()];
+};
+
+const fn foo() {
+    assert!([42, 55].len() > get_usize());
+    //~^ ERROR: unnecessary operation
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs
index de0081289ac..b4067c74074 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs
@@ -43,7 +43,7 @@ fn get_number() -> i32 {
     0
 }
 
-fn get_usize() -> usize {
+const fn get_usize() -> usize {
     0
 }
 fn get_struct() -> Struct {
@@ -117,4 +117,16 @@ fn main() {
     'label: {
         break 'label
     };
+    let () = const {
+        [42, 55][get_usize()];
+    };
+}
+
+const _: () = {
+    [42, 55][get_usize()];
+};
+
+const fn foo() {
+    [42, 55][get_usize()];
+    //~^ ERROR: unnecessary operation
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
index 27be5e6f4b9..036a9a44bba 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
@@ -119,5 +119,11 @@ LL | |         s: String::from("blah"),
 LL | |     };
    | |______^ help: statement can be reduced to: `String::from("blah");`
 
-error: aborting due to 19 previous errors
+error: unnecessary operation
+  --> tests/ui/unnecessary_operation.rs:130:5
+   |
+LL |     [42, 55][get_usize()];
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index 1afa5ab54c4..fdcac8fb08d 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -157,6 +157,25 @@ fn main() {
     require_path(&std::path::PathBuf::from("x"));
     require_str(&String::from("x"));
     require_slice(&[String::from("x")]);
+
+    let slice = [0u8; 1024];
+    let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8");
+    let _ref_str: &str = core::str::from_utf8(b"foo").unwrap();
+    let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap();
+    // Expression is of type `&String`, can't suggest `str::from_utf8` here
+    let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap();
+    macro_rules! arg_from_macro {
+        () => {
+            b"foo".to_vec()
+        };
+    }
+    macro_rules! string_from_utf8_from_macro {
+        () => {
+            &String::from_utf8(b"foo".to_vec()).unwrap()
+        };
+    }
+    let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap();
+    let _ref_str: &str = string_from_utf8_from_macro!();
 }
 
 fn require_c_str(_: &CStr) {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index aa88dde43bf..10a9727a9a7 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -157,6 +157,25 @@ fn main() {
     require_path(&std::path::PathBuf::from("x").to_path_buf());
     require_str(&String::from("x").to_string());
     require_slice(&[String::from("x")].to_owned());
+
+    let slice = [0u8; 1024];
+    let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8");
+    let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap();
+    let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap();
+    // Expression is of type `&String`, can't suggest `str::from_utf8` here
+    let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap();
+    macro_rules! arg_from_macro {
+        () => {
+            b"foo".to_vec()
+        };
+    }
+    macro_rules! string_from_utf8_from_macro {
+        () => {
+            &String::from_utf8(b"foo".to_vec()).unwrap()
+        };
+    }
+    let _ref_str: &str = &String::from_utf8(arg_from_macro!()).unwrap();
+    let _ref_str: &str = string_from_utf8_from_macro!();
 }
 
 fn require_c_str(_: &CStr) {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
index 2829f3cd6e9..511b4ae119f 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
@@ -477,8 +477,44 @@ error: unnecessary use of `to_owned`
 LL |     let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
 
+error: allocating a new `String` only to create a temporary `&str` from it
+  --> tests/ui/unnecessary_to_owned.rs:162:26
+   |
+LL |     let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8");
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert from `&[u8]` to `&str` directly
+   |
+LL -     let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8");
+LL +     let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8");
+   |
+
+error: allocating a new `String` only to create a temporary `&str` from it
+  --> tests/ui/unnecessary_to_owned.rs:163:26
+   |
+LL |     let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert from `&[u8]` to `&str` directly
+   |
+LL -     let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap();
+LL +     let _ref_str: &str = core::str::from_utf8(b"foo").unwrap();
+   |
+
+error: allocating a new `String` only to create a temporary `&str` from it
+  --> tests/ui/unnecessary_to_owned.rs:164:26
+   |
+LL |     let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert from `&[u8]` to `&str` directly
+   |
+LL -     let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap();
+LL +     let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap();
+   |
+
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:202:14
+  --> tests/ui/unnecessary_to_owned.rs:221:14
    |
 LL |     for t in file_types.to_vec() {
    |              ^^^^^^^^^^^^^^^^^^^
@@ -494,64 +530,64 @@ LL +         let path = match get_file_path(t) {
    |
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:225:14
+  --> tests/ui/unnecessary_to_owned.rs:244:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:230:14
+  --> tests/ui/unnecessary_to_owned.rs:249:14
    |
 LL |     let _ = &["x"][..].to_vec().into_iter();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()`
 
 error: unnecessary use of `to_string`
-  --> tests/ui/unnecessary_to_owned.rs:278:24
+  --> tests/ui/unnecessary_to_owned.rs:297:24
    |
 LL |         Box::new(build(y.to_string()))
    |                        ^^^^^^^^^^^^^ help: use: `y`
 
 error: unnecessary use of `to_string`
-  --> tests/ui/unnecessary_to_owned.rs:387:12
+  --> tests/ui/unnecessary_to_owned.rs:406:12
    |
 LL |         id("abc".to_string())
    |            ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:530:37
+  --> tests/ui/unnecessary_to_owned.rs:549:37
    |
 LL |         IntoFuture::into_future(foo([].to_vec(), &0));
    |                                     ^^^^^^^^^^^ help: use: `[]`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:540:18
+  --> tests/ui/unnecessary_to_owned.rs:559:18
    |
 LL |         s.remove(&a.to_vec());
    |                  ^^^^^^^^^^^ help: replace it with: `a`
 
 error: unnecessary use of `to_owned`
-  --> tests/ui/unnecessary_to_owned.rs:544:14
+  --> tests/ui/unnecessary_to_owned.rs:563:14
    |
 LL |     s.remove(&"b".to_owned());
    |              ^^^^^^^^^^^^^^^ help: replace it with: `"b"`
 
 error: unnecessary use of `to_string`
-  --> tests/ui/unnecessary_to_owned.rs:545:14
+  --> tests/ui/unnecessary_to_owned.rs:564:14
    |
 LL |     s.remove(&"b".to_string());
    |              ^^^^^^^^^^^^^^^^ help: replace it with: `"b"`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:550:14
+  --> tests/ui/unnecessary_to_owned.rs:569:14
    |
 LL |     s.remove(&["b"].to_vec());
    |              ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()`
 
 error: unnecessary use of `to_vec`
-  --> tests/ui/unnecessary_to_owned.rs:551:14
+  --> tests/ui/unnecessary_to_owned.rs:570:14
    |
 LL |     s.remove(&(&["b"]).to_vec());
    |              ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()`
 
-error: aborting due to 85 previous errors
+error: aborting due to 88 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
index 6fdd728b9b7..46890ee9213 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -204,6 +204,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -212,6 +213,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -219,6 +221,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs
index 20e06d4b366..1a5586cbb88 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports.rs
@@ -205,6 +205,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -213,6 +214,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -220,6 +222,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
index 0c69d5262c2..8e88f216394 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -106,31 +106,31 @@ LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:236:17
+  --> tests/ui/wildcard_imports.rs:239:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:244:13
+  --> tests/ui/wildcard_imports.rs:247:13
    |
 LL |         use crate::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:253:17
+  --> tests/ui/wildcard_imports.rs:256:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:262:13
+  --> tests/ui/wildcard_imports.rs:265:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports.rs:270:13
+  --> tests/ui/wildcard_imports.rs:273:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
index 6a9fe007d65..197dd3b94df 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
@@ -198,6 +198,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -206,6 +207,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -213,6 +215,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
index 11e0bd37769..66adacd95dc 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
@@ -106,31 +106,31 @@ LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:230:17
+  --> tests/ui/wildcard_imports_2021.rs:233:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:238:13
+  --> tests/ui/wildcard_imports_2021.rs:241:13
    |
 LL |         use crate::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:247:17
+  --> tests/ui/wildcard_imports_2021.rs:250:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:256:13
+  --> tests/ui/wildcard_imports_2021.rs:259:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:264:13
+  --> tests/ui/wildcard_imports_2021.rs:267:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
index 6a9fe007d65..197dd3b94df 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
@@ -198,6 +198,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -206,6 +207,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -213,6 +215,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
index 11e0bd37769..66adacd95dc 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
@@ -106,31 +106,31 @@ LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:230:17
+  --> tests/ui/wildcard_imports_2021.rs:233:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:238:13
+  --> tests/ui/wildcard_imports_2021.rs:241:13
    |
 LL |         use crate::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:247:17
+  --> tests/ui/wildcard_imports_2021.rs:250:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:256:13
+  --> tests/ui/wildcard_imports_2021.rs:259:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> tests/ui/wildcard_imports_2021.rs:264:13
+  --> tests/ui/wildcard_imports_2021.rs:267:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
index 18ebc0f5127..606ff080e77 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
@@ -199,6 +199,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass {
         use super::*;
 
@@ -207,6 +208,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_inside_function {
         fn with_super_inside_function() {
             use super::*;
@@ -214,6 +216,7 @@ mod super_imports {
         }
     }
 
+    #[cfg(test)]
     mod test_should_pass_further_inside {
         fn insidefoo() {}
         mod inner {
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 7479be90797..7f5d4f4b416 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -991,13 +991,19 @@ impl Config {
     }
 
     fn parse_custom_normalization(&self, line: &str, prefix: &str) -> Option<(String, String)> {
-        if parse_cfg_name_directive(self, line, prefix).outcome == MatchOutcome::Match {
-            let (regex, replacement) = parse_normalize_rule(line)
-                .unwrap_or_else(|| panic!("couldn't parse custom normalization rule: `{line}`"));
-            Some((regex, replacement))
-        } else {
-            None
+        let parsed = parse_cfg_name_directive(self, line, prefix);
+        if parsed.outcome != MatchOutcome::Match {
+            return None;
         }
+        let name = parsed.name.expect("successful match always has a name");
+
+        let Some((regex, replacement)) = parse_normalize_rule(line) else {
+            panic!(
+                "couldn't parse custom normalization rule: `{line}`\n\
+                help: expected syntax is: `{prefix}-{name}: \"REGEX\" -> \"REPLACEMENT\"`"
+            );
+        };
+        Some((regex, replacement))
     }
 
     fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index cd011dce784..ea1e573384b 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -298,6 +298,7 @@ impl<'a> Validator<'a> {
                 generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
             }
             GenericBound::Outlives(_) => {}
+            GenericBound::Use(_) => {}
         }
     }
 
diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs
index f246d71d499..9eaa234bfaf 100644
--- a/src/tools/lint-docs/src/groups.rs
+++ b/src/tools/lint-docs/src/groups.rs
@@ -37,7 +37,7 @@ impl<'a> LintExtractor<'a> {
             .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
         let new_contents =
             contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?);
-        // Delete the output because rustbuild uses hard links in its copies.
+        // Delete the output because bootstrap uses hard links in its copies.
         let _ = fs::remove_file(&groups_path);
         fs::write(&groups_path, new_contents)
             .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 72d6a495e7e..48e2dd09876 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -532,7 +532,7 @@ impl<'a> LintExtractor<'a> {
         }
         add_rename_redirect(level, &mut result);
         let out_path = self.out_path.join("listing").join(level.doc_filename());
-        // Delete the output because rustbuild uses hard links in its copies.
+        // Delete the output because bootstrap uses hard links in its copies.
         let _ = fs::remove_file(&out_path);
         fs::write(&out_path, result)
             .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?;
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 8d48b9c8ad1..3743446e276 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -104,9 +104,17 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
             miri_for_host()
         )
     });
-    let host = &rustc_version.host;
-    let target = get_arg_flag_value("--target");
-    let target = target.as_ref().unwrap_or(host);
+    let mut targets = get_arg_flag_values("--target").collect::<Vec<_>>();
+    // If `targets` is empty, we need to add a `--target $HOST` flag ourselves, and also ensure
+    // that the host target is indeed setup.
+    let target_flag = if targets.is_empty() {
+        let host = &rustc_version.host;
+        targets.push(host.clone());
+        Some(host)
+    } else {
+        // We don't need to add a `--target` flag, we just forward the user's flags.
+        None
+    };
 
     // If cleaning the target directory & sysroot cache,
     // delete them then exit. There is no reason to setup a new
@@ -118,8 +126,11 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
         return;
     }
 
-    // We always setup.
-    let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose, quiet);
+    for target in &targets {
+        // We always setup.
+        setup(&subcommand, target.as_str(), &rustc_version, verbose, quiet);
+    }
+    let miri_sysroot = get_sysroot_dir();
 
     // Invoke actual cargo for the job, but with different flags.
     // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but
@@ -155,10 +166,9 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     // This is needed to make the `target.runner` settings do something,
     // and it later helps us detect which crates are proc-macro/build-script
     // (host crates) and which crates are needed for the program itself.
-    if get_arg_flag_value("--target").is_none() {
-        // No target given. Explicitly pick the host.
+    if let Some(target_flag) = target_flag {
         cmd.arg("--target");
-        cmd.arg(host);
+        cmd.arg(target_flag);
     }
 
     // Set ourselves as runner for al binaries invoked by cargo.
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 67985f9b7d6..5e75638f467 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -41,9 +41,11 @@ function run_tests {
   if [ -n "${TEST_TARGET-}" ]; then
     begingroup "Testing foreign architecture $TEST_TARGET"
     TARGET_FLAG="--target $TEST_TARGET"
+    MULTI_TARGET_FLAG=""
   else
     begingroup "Testing host architecture"
     TARGET_FLAG=""
+    MULTI_TARGET_FLAG="--multi-target"
   fi
 
   ## ui test suite
@@ -93,7 +95,7 @@ function run_tests {
     echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml
   fi
   # Run the actual test
-  time ${PYTHON} test-cargo-miri/run-test.py $TARGET_FLAG
+  time ${PYTHON} test-cargo-miri/run-test.py $TARGET_FLAG $MULTI_TARGET_FLAG
   # Clean up
   unset RUSTC MIRI
   rm -rf .cargo
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 5a35166769e..e90d3732ca5 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-66b4f0021bfb11a8c20d084c99a40f4a78ce1d38
+99b7134389e9766462601a2fc4013840b9d31745
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 9d8e44ce409..9f3fa075f38 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -592,6 +592,9 @@ fn main() {
             let num_cpus = param
                 .parse::<u32>()
                 .unwrap_or_else(|err| show_error!("-Zmiri-num-cpus requires a `u32`: {}", err));
+            if !(1..=miri::MAX_CPUS).contains(&usize::try_from(num_cpus).unwrap()) {
+                show_error!("-Zmiri-num-cpus must be in the range 1..={}", miri::MAX_CPUS);
+            }
             miri_config.num_cpus = num_cpus;
         } else if let Some(param) = arg.strip_prefix("-Zmiri-force-page-size=") {
             let page_size = param.parse::<u64>().unwrap_or_else(|err| {
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
index f65f49a75dd..774b36919fe 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
@@ -136,8 +136,16 @@ impl StackCache {
 
 impl PartialEq for Stack {
     fn eq(&self, other: &Self) -> bool {
-        // All the semantics of Stack are in self.borrows, everything else is caching
-        self.borrows == other.borrows
+        let Stack {
+            borrows,
+            unknown_bottom,
+            // The cache is ignored for comparison.
+            #[cfg(feature = "stack-cache")]
+                cache: _,
+            #[cfg(feature = "stack-cache")]
+                unique_range: _,
+        } = self;
+        *borrows == other.borrows && *unknown_bottom == other.unknown_bottom
     }
 }
 
diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs
new file mode 100644
index 00000000000..8df26d718bf
--- /dev/null
+++ b/src/tools/miri/src/concurrency/cpu_affinity.rs
@@ -0,0 +1,90 @@
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_target::abi::Endian;
+
+use crate::*;
+
+/// The maximum number of CPUs supported by miri.
+///
+/// This value is compatible with the libc `CPU_SETSIZE` constant and corresponds to the number
+/// of CPUs that a `cpu_set_t` can contain.
+///
+/// Real machines can have more CPUs than this number, and there exist APIs to set their affinity,
+/// but this is not currently supported by miri.
+pub const MAX_CPUS: usize = 1024;
+
+/// A thread's CPU affinity mask determines the set of CPUs on which it is eligible to run.
+// the actual representation depends on the target's endianness and pointer width.
+// See CpuAffinityMask::set for details
+#[derive(Clone)]
+pub(crate) struct CpuAffinityMask([u8; Self::CPU_MASK_BYTES]);
+
+impl CpuAffinityMask {
+    pub(crate) const CPU_MASK_BYTES: usize = MAX_CPUS / 8;
+
+    pub fn new<'tcx>(cx: &impl LayoutOf<'tcx>, cpu_count: u32) -> Self {
+        let mut this = Self([0; Self::CPU_MASK_BYTES]);
+
+        // the default affinity mask includes only the available CPUs
+        for i in 0..cpu_count as usize {
+            this.set(cx, i);
+        }
+
+        this
+    }
+
+    pub fn chunk_size<'tcx>(cx: &impl LayoutOf<'tcx>) -> u64 {
+        // The actual representation of the CpuAffinityMask is [c_ulong; _].
+        let ulong = helpers::path_ty_layout(cx, &["core", "ffi", "c_ulong"]);
+        ulong.size.bytes()
+    }
+
+    fn set<'tcx>(&mut self, cx: &impl LayoutOf<'tcx>, cpu: usize) {
+        // we silently ignore CPUs that are out of bounds. This matches the behavior of
+        // `sched_setaffinity` with a mask that specifies more than `CPU_SETSIZE` CPUs.
+        if cpu >= MAX_CPUS {
+            return;
+        }
+
+        // The actual representation of the CpuAffinityMask is [c_ulong; _].
+        // Within the array elements, we need to use the endianness of the target.
+        let target = &cx.tcx().sess.target;
+        match Self::chunk_size(cx) {
+            4 => {
+                let start = cpu / 32 * 4; // first byte of the correct u32
+                let chunk = self.0[start..].first_chunk_mut::<4>().unwrap();
+                let offset = cpu % 32;
+                *chunk = match target.options.endian {
+                    Endian::Little => (u32::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(),
+                    Endian::Big => (u32::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
+                };
+            }
+            8 => {
+                let start = cpu / 64 * 8; // first byte of the correct u64
+                let chunk = self.0[start..].first_chunk_mut::<8>().unwrap();
+                let offset = cpu % 64;
+                *chunk = match target.options.endian {
+                    Endian::Little => (u64::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(),
+                    Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
+                };
+            }
+            other => bug!("chunk size not supported: {other}"),
+        };
+    }
+
+    pub fn as_slice(&self) -> &[u8] {
+        self.0.as_slice()
+    }
+
+    pub fn from_array<'tcx>(
+        cx: &impl LayoutOf<'tcx>,
+        cpu_count: u32,
+        bytes: [u8; Self::CPU_MASK_BYTES],
+    ) -> Option<Self> {
+        // mask by what CPUs are actually available
+        let default = Self::new(cx, cpu_count);
+        let masked = std::array::from_fn(|i| bytes[i] & default.0[i]);
+
+        // at least one thread must be set for the input to be valid
+        masked.iter().any(|b| *b != 0).then_some(Self(masked))
+    }
+}
diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs
index 822d173ac06..17789fe9f87 100644
--- a/src/tools/miri/src/concurrency/mod.rs
+++ b/src/tools/miri/src/concurrency/mod.rs
@@ -1,3 +1,4 @@
+pub mod cpu_affinity;
 pub mod data_race;
 pub mod init_once;
 mod range_object_map;
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index 91865a2192c..d0c9a4600e8 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -269,7 +269,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         if this.mutex_is_locked(mutex) {
             assert_ne!(this.mutex_get_owner(mutex), this.active_thread());
-            this.mutex_enqueue_and_block(mutex, retval, dest);
+            this.mutex_enqueue_and_block(mutex, Some((retval, dest)));
         } else {
             // We can have it right now!
             this.mutex_lock(mutex);
@@ -390,9 +390,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     /// Put the thread into the queue waiting for the mutex.
-    /// Once the Mutex becomes available, `retval` will be written to `dest`.
+    ///
+    /// Once the Mutex becomes available and if it exists, `retval_dest.0` will
+    /// be written to `retval_dest.1`.
     #[inline]
-    fn mutex_enqueue_and_block(&mut self, id: MutexId, retval: Scalar, dest: MPlaceTy<'tcx>) {
+    fn mutex_enqueue_and_block(
+        &mut self,
+        id: MutexId,
+        retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
+    ) {
         let this = self.eval_context_mut();
         assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
         let thread = this.active_thread();
@@ -403,13 +409,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             callback!(
                 @capture<'tcx> {
                     id: MutexId,
-                    retval: Scalar,
-                    dest: MPlaceTy<'tcx>,
+                    retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
                 }
                 @unblock = |this| {
                     assert!(!this.mutex_is_locked(id));
                     this.mutex_lock(id);
-                    this.write_scalar(retval, &dest)?;
+
+                    if let Some((retval, dest)) = retval_dest {
+                        this.write_scalar(retval, &dest)?;
+                    }
+
                     Ok(())
                 }
             ),
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 718daf93ea0..a53dd7eac1e 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -936,6 +936,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // After this all accesses will be treated as occurring in the new thread.
         let old_thread_id = this.machine.threads.set_active_thread_id(new_thread_id);
 
+        // The child inherits its parent's cpu affinity.
+        if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&old_thread_id).cloned() {
+            this.machine.thread_cpu_affinity.insert(new_thread_id, cpuset);
+        }
+
         // Perform the function pointer load in the new thread frame.
         let instance = this.get_ptr_fn(start_routine)?.as_instance()?;
 
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 9142b8b5fdb..2184a4426c8 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -282,7 +282,8 @@ pub fn create_ecx<'tcx>(
     })?;
 
     // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
-    let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
+    let sentinel =
+        helpers::try_resolve_path(tcx, &["core", "ascii", "escape_default"], Namespace::ValueNS);
     if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
         tcx.dcx().fatal(
             "the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 590e8984e99..ba094c988e5 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -18,6 +18,7 @@ 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::{
     self,
     layout::{LayoutOf, TyAndLayout},
@@ -159,6 +160,35 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>)
     None
 }
 
+/// Gets an instance for a path; fails gracefully if the path does not exist.
+pub fn try_resolve_path<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    path: &[&str],
+    namespace: Namespace,
+) -> Option<ty::Instance<'tcx>> {
+    let did = try_resolve_did(tcx, path, Some(namespace))?;
+    Some(ty::Instance::mono(tcx, did))
+}
+
+/// Gets an instance for a path.
+#[track_caller]
+pub fn resolve_path<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    path: &[&str],
+    namespace: Namespace,
+) -> ty::Instance<'tcx> {
+    try_resolve_path(tcx, path, namespace)
+        .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
+}
+
+/// Gets the layout of a type at a path.
+#[track_caller]
+pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> {
+    let ty =
+        resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), ty::ParamEnv::reveal_all());
+    cx.layout_of(ty).to_result().ok().unwrap()
+}
+
 /// Call `f` for each exported symbol.
 pub fn iter_exported_symbols<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -259,23 +289,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
     }
 
-    /// Gets an instance for a path; fails gracefully if the path does not exist.
-    fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
-        let tcx = self.eval_context_ref().tcx.tcx;
-        let did = try_resolve_did(tcx, path, Some(namespace))?;
-        Some(ty::Instance::mono(tcx, did))
-    }
-
-    /// Gets an instance for a path.
-    fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> {
-        self.try_resolve_path(path, namespace)
-            .unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
-    }
-
     /// Evaluates the scalar at the specified path.
     fn eval_path(&self, path: &[&str]) -> OpTy<'tcx> {
         let this = self.eval_context_ref();
-        let instance = this.resolve_path(path, Namespace::ValueNS);
+        let instance = resolve_path(*this.tcx, path, Namespace::ValueNS);
         // We don't give a span -- this isn't actually used directly by the program anyway.
         let const_val = this.eval_global(instance).unwrap_or_else(|err| {
             panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
@@ -344,19 +361,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 "`libc` crate is not reliably available on Windows targets; Miri should not use it there"
             );
         }
-        let ty = this
-            .resolve_path(&["libc", name], Namespace::TypeNS)
-            .ty(*this.tcx, ty::ParamEnv::reveal_all());
-        this.layout_of(ty).unwrap()
+        path_ty_layout(this, &["libc", name])
     }
 
     /// Helper function to get the `TyAndLayout` of a `windows` type
     fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
         let this = self.eval_context_ref();
-        let ty = this
-            .resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS)
-            .ty(*this.tcx, ty::ParamEnv::reveal_all());
-        this.layout_of(ty).unwrap()
+        path_ty_layout(this, &["std", "sys", "pal", "windows", "c", name])
     }
 
     /// Project to the given *named* field (which must be a struct or union type).
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 313eac36337..9cd776c9371 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -392,10 +392,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         bug!("float_finite: non-float input type {}", x.layout.ty)
                     };
                     Ok(match fty {
-                        FloatTy::F16 => unimplemented!("f16_f128"),
+                        FloatTy::F16 => x.to_scalar().to_f16()?.is_finite(),
                         FloatTy::F32 => x.to_scalar().to_f32()?.is_finite(),
                         FloatTy::F64 => x.to_scalar().to_f64()?.is_finite(),
-                        FloatTy::F128 => unimplemented!("f16_f128"),
+                        FloatTy::F128 => x.to_scalar().to_f128()?.is_finite(),
                     })
                 };
                 match (float_finite(&a)?, float_finite(&b)?) {
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 8da00861f90..7fb68d782f1 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -129,6 +129,7 @@ pub use crate::borrow_tracker::{
 };
 pub use crate::clock::{Clock, Instant};
 pub use crate::concurrency::{
+    cpu_affinity::MAX_CPUS,
     data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _},
     init_once::{EvalContextExt as _, InitOnceId},
     sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects},
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 714d97823f4..adb84593561 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -30,6 +30,7 @@ use rustc_target::spec::abi::Abi;
 
 use crate::{
     concurrency::{
+        cpu_affinity::{self, CpuAffinityMask},
         data_race::{self, NaReadType, NaWriteType},
         weak_memory,
     },
@@ -471,6 +472,12 @@ pub struct MiriMachine<'tcx> {
 
     /// The set of threads.
     pub(crate) threads: ThreadManager<'tcx>,
+
+    /// Stores which thread is eligible to run on which CPUs.
+    /// This has no effect at all, it is just tracked to produce the correct result
+    /// in `sched_getaffinity`
+    pub(crate) thread_cpu_affinity: FxHashMap<ThreadId, CpuAffinityMask>,
+
     /// The state of the primitive synchronization objects.
     pub(crate) sync: SynchronizationObjects,
 
@@ -627,6 +634,18 @@ impl<'tcx> MiriMachine<'tcx> {
         let stack_addr = if tcx.pointer_size().bits() < 32 { page_size } else { page_size * 32 };
         let stack_size =
             if tcx.pointer_size().bits() < 32 { page_size * 4 } else { page_size * 16 };
+        assert!(
+            usize::try_from(config.num_cpus).unwrap() <= cpu_affinity::MAX_CPUS,
+            "miri only supports up to {} CPUs, but {} were configured",
+            cpu_affinity::MAX_CPUS,
+            config.num_cpus
+        );
+        let threads = ThreadManager::default();
+        let mut thread_cpu_affinity = FxHashMap::default();
+        if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") {
+            thread_cpu_affinity
+                .insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus));
+        }
         MiriMachine {
             tcx,
             borrow_tracker,
@@ -644,7 +663,8 @@ impl<'tcx> MiriMachine<'tcx> {
             fds: shims::FdTable::new(config.mute_stdout_stderr),
             dirs: Default::default(),
             layouts,
-            threads: ThreadManager::default(),
+            threads,
+            thread_cpu_affinity,
             sync: SynchronizationObjects::default(),
             static_roots: Vec::new(),
             profiler,
@@ -765,6 +785,7 @@ impl VisitProvenance for MiriMachine<'_> {
         #[rustfmt::skip]
         let MiriMachine {
             threads,
+            thread_cpu_affinity: _,
             sync: _,
             tls,
             env_vars,
diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs
index af980ca4819..8edd80744dd 100644
--- a/src/tools/miri/src/provenance_gc.rs
+++ b/src/tools/miri/src/provenance_gc.rs
@@ -30,6 +30,17 @@ impl<T: VisitProvenance> VisitProvenance for Option<T> {
     }
 }
 
+impl<A, B> VisitProvenance for (A, B)
+where
+    A: VisitProvenance,
+    B: VisitProvenance,
+{
+    fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
+        self.0.visit_provenance(visit);
+        self.1.visit_provenance(visit);
+    }
+}
+
 impl<T: VisitProvenance> VisitProvenance for std::cell::RefCell<T> {
     fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
         self.borrow().visit_provenance(visit)
diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs
index c91386fa877..87074468789 100644
--- a/src/tools/miri/src/shims/tls.rs
+++ b/src/tools/miri/src/shims/tls.rs
@@ -36,9 +36,9 @@ pub struct TlsData<'tcx> {
     /// pthreads-style thread-local storage.
     keys: BTreeMap<TlsKey, TlsEntry<'tcx>>,
 
-    /// A single per thread destructor of the thread local storage (that's how
-    /// things work on macOS) with a data argument.
-    macos_thread_dtors: BTreeMap<ThreadId, (ty::Instance<'tcx>, Scalar)>,
+    /// On macOS, each thread holds a list of destructor functions with their
+    /// respective data arguments.
+    macos_thread_dtors: BTreeMap<ThreadId, Vec<(ty::Instance<'tcx>, Scalar)>>,
 }
 
 impl<'tcx> Default for TlsData<'tcx> {
@@ -119,26 +119,15 @@ impl<'tcx> TlsData<'tcx> {
         }
     }
 
-    /// Set the thread wide destructor of the thread local storage for the given
-    /// thread. This function is used to implement `_tlv_atexit` shim on MacOS.
-    ///
-    /// Thread wide dtors are available only on MacOS. There is one destructor
-    /// per thread as can be guessed from the following comment in the
-    /// [`_tlv_atexit`
-    /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389):
-    ///
-    /// NOTE: this does not need locks because it only operates on current thread data
-    pub fn set_macos_thread_dtor(
+    /// Add a thread local storage destructor for the given thread. This function
+    /// is used to implement the `_tlv_atexit` shim on MacOS.
+    pub fn add_macos_thread_dtor(
         &mut self,
         thread: ThreadId,
         dtor: ty::Instance<'tcx>,
         data: Scalar,
     ) -> InterpResult<'tcx> {
-        if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() {
-            throw_unsup_format!(
-                "setting more than one thread local storage destructor for the same thread is not supported"
-            );
-        }
+        self.macos_thread_dtors.entry(thread).or_default().push((dtor, data));
         Ok(())
     }
 
@@ -202,6 +191,10 @@ impl<'tcx> TlsData<'tcx> {
         for TlsEntry { data, .. } in self.keys.values_mut() {
             data.remove(&thread_id);
         }
+
+        if let Some(dtors) = self.macos_thread_dtors.remove(&thread_id) {
+            assert!(dtors.is_empty(), "the destructors should have already been run");
+        }
     }
 }
 
@@ -212,7 +205,7 @@ impl VisitProvenance for TlsData<'_> {
         for scalar in keys.values().flat_map(|v| v.data.values()) {
             scalar.visit_provenance(visit);
         }
-        for (_, scalar) in macos_thread_dtors.values() {
+        for (_, scalar) in macos_thread_dtors.values().flatten() {
             scalar.visit_provenance(visit);
         }
     }
@@ -225,6 +218,7 @@ pub struct TlsDtorsState<'tcx>(TlsDtorsStatePriv<'tcx>);
 enum TlsDtorsStatePriv<'tcx> {
     #[default]
     Init,
+    MacOsDtors,
     PthreadDtors(RunningDtorState),
     /// For Windows Dtors, we store the list of functions that we still have to call.
     /// These are functions from the magic `.CRT$XLB` linker section.
@@ -243,11 +237,10 @@ impl<'tcx> TlsDtorsState<'tcx> {
                 Init => {
                     match this.tcx.sess.target.os.as_ref() {
                         "macos" => {
-                            // The macOS thread wide destructor runs "before any TLS slots get
-                            // freed", so do that first.
-                            this.schedule_macos_tls_dtor()?;
-                            // When that destructor is done, go on with the pthread dtors.
-                            break 'new_state PthreadDtors(Default::default());
+                            // macOS has a _tlv_atexit function that allows
+                            // registering destructors without associated keys.
+                            // These are run first.
+                            break 'new_state MacOsDtors;
                         }
                         _ if this.target_os_is_unix() => {
                             // All other Unixes directly jump to running the pthread dtors.
@@ -266,6 +259,14 @@ impl<'tcx> TlsDtorsState<'tcx> {
                         }
                     }
                 }
+                MacOsDtors => {
+                    match this.schedule_macos_tls_dtor()? {
+                        Poll::Pending => return Ok(Poll::Pending),
+                        // After all macOS destructors are run, the system switches
+                        // to destroying the pthread destructors.
+                        Poll::Ready(()) => break 'new_state PthreadDtors(Default::default()),
+                    }
+                }
                 PthreadDtors(state) => {
                     match this.schedule_next_pthread_tls_dtor(state)? {
                         Poll::Pending => return Ok(Poll::Pending), // just keep going
@@ -328,12 +329,15 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    /// Schedule the MacOS thread destructor of the thread local storage to be
-    /// executed.
-    fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx> {
+    /// Schedule the macOS thread local storage destructors to be executed.
+    fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, Poll<()>> {
         let this = self.eval_context_mut();
         let thread_id = this.active_thread();
-        if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) {
+        // macOS keeps track of TLS destructors in a stack. If a destructor
+        // registers another destructor, it will be run next.
+        // See https://github.com/apple-oss-distributions/dyld/blob/d552c40cd1de105f0ec95008e0e0c0972de43456/dyld/DyldRuntimeState.cpp#L2277
+        let dtor = this.machine.tls.macos_thread_dtors.get_mut(&thread_id).and_then(Vec::pop);
+        if let Some((instance, data)) = dtor {
             trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id);
 
             this.call_function(
@@ -343,8 +347,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 None,
                 StackPopCleanup::Root { cleanup: true },
             )?;
+
+            return Ok(Poll::Pending);
         }
-        Ok(())
+
+        Ok(Poll::Ready(()))
     }
 
     /// Schedule a pthread TLS destructor. Returns `true` if found
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 7f6a0978103..8fb046b5e64 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -419,7 +419,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match result {
             Ok(read_bytes) => {
                 // If reading to `bytes` did not fail, we write those bytes to the buffer.
-                this.write_bytes_ptr(buf, bytes)?;
+                // Crucially, if fewer than `bytes.len()` bytes were read, only write
+                // that much into the output buffer!
+                this.write_bytes_ptr(
+                    buf,
+                    bytes[..usize::try_from(read_bytes).unwrap()].iter().copied(),
+                )?;
                 Ok(read_bytes)
             }
             Err(e) => {
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 2421f9244f3..3a18d622033 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -3,8 +3,10 @@ use std::str;
 
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_span::Symbol;
+use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
+use crate::concurrency::cpu_affinity::CpuAffinityMask;
 use crate::shims::alloc::EvalContextExt as _;
 use crate::shims::unix::*;
 use crate::*;
@@ -571,6 +573,99 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = this.nanosleep(req, rem)?;
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
+            "sched_getaffinity" => {
+                // Currently this function does not exist on all Unixes, e.g. on macOS.
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") {
+                    throw_unsup_format!(
+                        "`sched_getaffinity` is not supported on {}",
+                        this.tcx.sess.target.os
+                    );
+                }
+
+                let [pid, cpusetsize, mask] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let pid = this.read_scalar(pid)?.to_u32()?;
+                let cpusetsize = this.read_target_usize(cpusetsize)?;
+                let mask = this.read_pointer(mask)?;
+
+                // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
+                let thread_id = match pid {
+                    0 => this.active_thread(),
+                    _ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"),
+                };
+
+                // The mask is stored in chunks, and the size must be a whole number of chunks.
+                let chunk_size = CpuAffinityMask::chunk_size(this);
+
+                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)?;
+                } 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)?;
+                } 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)?;
+                } 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)?;
+                }
+            }
+            "sched_setaffinity" => {
+                // Currently this function does not exist on all Unixes, e.g. on macOS.
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") {
+                    throw_unsup_format!(
+                        "`sched_setaffinity` is not supported on {}",
+                        this.tcx.sess.target.os
+                    );
+                }
+
+                let [pid, cpusetsize, mask] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let pid = this.read_scalar(pid)?.to_u32()?;
+                let cpusetsize = this.read_target_usize(cpusetsize)?;
+                let mask = this.read_pointer(mask)?;
+
+                // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
+                let thread_id = match pid {
+                    0 => this.active_thread(),
+                    _ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"),
+                };
+
+                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)?;
+                } 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).
+                    // This is not exactly documented, so we assume that this is the behavior in practice.
+                    let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
+                    // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
+                    let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
+                        std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
+                    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)?;
+                        }
+                        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)?;
+                        }
+                    }
+                }
+            }
 
             // Miscellaneous
             "isatty" => {
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 e31d43d9190..95bee38cd78 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -178,19 +178,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?;
             }
-            "sched_getaffinity" => {
-                // This shim isn't useful, aside from the fact that it makes `num_cpus`
-                // fall back to `sysconf` where it will successfully determine the number of CPUs.
-                let [pid, cpusetsize, mask] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                this.read_scalar(pid)?.to_i32()?;
-                this.read_target_usize(cpusetsize)?;
-                this.deref_pointer_as(mask, this.libc_ty_layout("cpu_set_t"))?;
-                // FIXME: we just return an error.
-                let einval = this.eval_libc("EINVAL");
-                this.set_last_error(einval)?;
-                this.write_scalar(Scalar::from_i32(-1), dest)?;
-            }
 
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
             // These shims are enabled only when the caller is in the standard library.
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 25002f0a611..47b887dec94 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -1,6 +1,7 @@
 use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
 
+use super::sync::EvalContextExt as _;
 use crate::shims::unix::*;
 use crate::*;
 
@@ -132,7 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
                 let data = this.read_scalar(data)?;
                 let active_thread = this.active_thread();
-                this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
+                this.machine.tls.add_macos_thread_dtor(active_thread, dtor, data)?;
             }
 
             // Querying system information
@@ -174,6 +175,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
 
+            "os_unfair_lock_lock" => {
+                let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                this.os_unfair_lock_lock(lock_op)?;
+            }
+            "os_unfair_lock_trylock" => {
+                let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                this.os_unfair_lock_trylock(lock_op, dest)?;
+            }
+            "os_unfair_lock_unlock" => {
+                let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                this.os_unfair_lock_unlock(lock_op)?;
+            }
+            "os_unfair_lock_assert_owner" => {
+                let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                this.os_unfair_lock_assert_owner(lock_op)?;
+            }
+            "os_unfair_lock_assert_not_owner" => {
+                let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                this.os_unfair_lock_assert_not_owner(lock_op)?;
+            }
+
             _ => return Ok(EmulateItemResult::NotSupported),
         };
 
diff --git a/src/tools/miri/src/shims/unix/macos/mod.rs b/src/tools/miri/src/shims/unix/macos/mod.rs
index 09c6507b24f..50fb2b9d328 100644
--- a/src/tools/miri/src/shims/unix/macos/mod.rs
+++ b/src/tools/miri/src/shims/unix/macos/mod.rs
@@ -1 +1,2 @@
 pub mod foreign_items;
+pub mod sync;
diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs
new file mode 100644
index 00000000000..5e5fccb587b
--- /dev/null
+++ b/src/tools/miri/src/shims/unix/macos/sync.rs
@@ -0,0 +1,107 @@
+//! Contains macOS-specific synchronization functions.
+//!
+//! For `os_unfair_lock`, see the documentation
+//! <https://developer.apple.com/documentation/os/synchronization?language=objc>
+//! and in case of underspecification its implementation
+//! <https://github.com/apple-oss-distributions/libplatform/blob/a00a4cc36da2110578bcf3b8eeeeb93dcc7f4e11/src/os/lock.c#L645>.
+//!
+//! Note that we don't emulate every edge-case behaviour of the locks. Notably,
+//! we don't abort when locking a lock owned by a thread that has already exited
+//! and we do not detect copying of the lock, but macOS doesn't guarantee anything
+//! in that case either.
+
+use crate::*;
+
+impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
+trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    fn os_unfair_lock_getid(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> {
+        let this = self.eval_context_mut();
+        // os_unfair_lock holds a 32-bit value, is initialized with zero and
+        // must be assumed to be opaque. Therefore, we can just store our
+        // internal mutex ID in the structure without anyone noticing.
+        this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0)
+    }
+}
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    fn os_unfair_lock_lock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        let id = this.os_unfair_lock_getid(lock_op)?;
+        if this.mutex_is_locked(id) {
+            if this.mutex_get_owner(id) == this.active_thread() {
+                // Matching the current macOS implementation: abort on reentrant locking.
+                throw_machine_stop!(TerminationInfo::Abort(
+                    "attempted to lock an os_unfair_lock that is already locked by the current thread".to_owned()
+                ));
+            }
+
+            this.mutex_enqueue_and_block(id, None);
+        } else {
+            this.mutex_lock(id);
+        }
+
+        Ok(())
+    }
+
+    fn os_unfair_lock_trylock(
+        &mut self,
+        lock_op: &OpTy<'tcx>,
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        let id = this.os_unfair_lock_getid(lock_op)?;
+        if this.mutex_is_locked(id) {
+            // Contrary to the blocking lock function, this does not check for
+            // reentrancy.
+            this.write_scalar(Scalar::from_bool(false), dest)?;
+        } else {
+            this.mutex_lock(id);
+            this.write_scalar(Scalar::from_bool(true), dest)?;
+        }
+
+        Ok(())
+    }
+
+    fn os_unfair_lock_unlock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        let id = this.os_unfair_lock_getid(lock_op)?;
+        if this.mutex_unlock(id)?.is_none() {
+            // Matching the current macOS implementation: abort.
+            throw_machine_stop!(TerminationInfo::Abort(
+                "attempted to unlock an os_unfair_lock not owned by the current thread".to_owned()
+            ));
+        }
+
+        Ok(())
+    }
+
+    fn os_unfair_lock_assert_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        let id = this.os_unfair_lock_getid(lock_op)?;
+        if !this.mutex_is_locked(id) || this.mutex_get_owner(id) != this.active_thread() {
+            throw_machine_stop!(TerminationInfo::Abort(
+                "called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned()
+            ));
+        }
+
+        Ok(())
+    }
+
+    fn os_unfair_lock_assert_not_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+
+        let id = this.os_unfair_lock_getid(lock_op)?;
+        if this.mutex_is_locked(id) && this.mutex_get_owner(id) == this.active_thread() {
+            throw_machine_stop!(TerminationInfo::Abort(
+                "called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread".to_owned()
+            ));
+        }
+
+        Ok(())
+    }
+}
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index be6732b1b67..e8653117ae9 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -473,7 +473,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let ret = if this.mutex_is_locked(id) {
             let owner_thread = this.mutex_get_owner(id);
             if owner_thread != this.active_thread() {
-                this.mutex_enqueue_and_block(id, Scalar::from_i32(0), dest.clone());
+                this.mutex_enqueue_and_block(id, Some((Scalar::from_i32(0), dest.clone())));
                 return Ok(());
             } else {
                 // Trying to acquire the same mutex again.
diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py
index d855c333a75..5b77092979d 100755
--- a/src/tools/miri/test-cargo-miri/run-test.py
+++ b/src/tools/miri/test-cargo-miri/run-test.py
@@ -22,12 +22,17 @@ def fail(msg):
     print("\nTEST FAIL: {}".format(msg))
     sys.exit(1)
 
-def cargo_miri(cmd, quiet = True):
+def cargo_miri(cmd, quiet = True, targets = None):
     args = ["cargo", "miri", cmd] + CARGO_EXTRA_FLAGS
     if quiet:
         args += ["-q"]
-    if ARGS.target:
+
+    if targets is not None:
+        for target in targets:
+            args.extend(("--target", target))
+    elif ARGS.target is not None:
         args += ["--target", ARGS.target]
+
     return args
 
 def normalize_stdout(str):
@@ -186,10 +191,21 @@ def test_cargo_miri_test():
         default_ref, "test.stderr-empty.ref",
         env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
     )
+    if ARGS.multi_target:
+        test_cargo_miri_multi_target()
+
+
+def test_cargo_miri_multi_target():
+    test("`cargo miri test` (multiple targets)",
+        cargo_miri("test", targets = ["aarch64-unknown-linux-gnu", "s390x-unknown-linux-gnu"]),
+        "test.multiple_targets.stdout.ref", "test.stderr-empty.ref",
+        env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
+    )
 
 args_parser = argparse.ArgumentParser(description='`cargo miri` testing')
 args_parser.add_argument('--target', help='the target to test')
 args_parser.add_argument('--bless', help='bless the reference files', action='store_true')
+args_parser.add_argument('--multi-target', help='run tests related to multiple targets', action='store_true')
 ARGS = args_parser.parse_args()
 
 os.chdir(os.path.dirname(os.path.realpath(__file__)))
diff --git a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref
new file mode 100644
index 00000000000..567c5db07d0
--- /dev/null
+++ b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref
@@ -0,0 +1,22 @@
+
+running 2 tests
+..
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
+
+running 2 tests
+..
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
+imported main
+imported main
+
+running 6 tests
+...i..
+test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
+
+running 6 tests
+...i..
+test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs
new file mode 100644
index 00000000000..d6604f37139
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs
@@ -0,0 +1,13 @@
+//@ only-target-darwin
+
+use std::cell::UnsafeCell;
+
+fn main() {
+    let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
+
+    unsafe {
+        libc::os_unfair_lock_lock(lock.get());
+        libc::os_unfair_lock_assert_not_owner(lock.get());
+        //~^ error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr
new file mode 100644
index 00000000000..7e890681c43
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr
@@ -0,0 +1,13 @@
+error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread
+  --> $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC
+   |
+LL |         libc::os_unfair_lock_assert_not_owner(lock.get());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/apple_os_unfair_lock_assert_not_owner.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/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs
new file mode 100644
index 00000000000..ddd8b572eaf
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs
@@ -0,0 +1,12 @@
+//@ only-target-darwin
+
+use std::cell::UnsafeCell;
+
+fn main() {
+    let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
+
+    unsafe {
+        libc::os_unfair_lock_assert_owner(lock.get());
+        //~^ error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr
new file mode 100644
index 00000000000..3724f7996fb
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr
@@ -0,0 +1,13 @@
+error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread
+  --> $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC
+   |
+LL |         libc::os_unfair_lock_assert_owner(lock.get());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/apple_os_unfair_lock_assert_owner.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/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs
new file mode 100644
index 00000000000..eb98adeba07
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs
@@ -0,0 +1,13 @@
+//@ only-target-darwin
+
+use std::cell::UnsafeCell;
+
+fn main() {
+    let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
+
+    unsafe {
+        libc::os_unfair_lock_lock(lock.get());
+        libc::os_unfair_lock_lock(lock.get());
+        //~^ error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr
new file mode 100644
index 00000000000..644462a1b05
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr
@@ -0,0 +1,13 @@
+error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread
+  --> $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC
+   |
+LL |         libc::os_unfair_lock_lock(lock.get());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to lock an os_unfair_lock that is already locked by the current thread
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/apple_os_unfair_lock_reentrant.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/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs
new file mode 100644
index 00000000000..aed467552ab
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs
@@ -0,0 +1,12 @@
+//@ only-target-darwin
+
+use std::cell::UnsafeCell;
+
+fn main() {
+    let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
+
+    unsafe {
+        libc::os_unfair_lock_unlock(lock.get());
+        //~^ error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr
new file mode 100644
index 00000000000..6a8d12fa807
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr
@@ -0,0 +1,13 @@
+error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread
+  --> $DIR/apple_os_unfair_lock_unowned.rs:LL:CC
+   |
+LL |         libc::os_unfair_lock_unlock(lock.get());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to unlock an os_unfair_lock not owned by the current thread
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/apple_os_unfair_lock_unowned.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/fail-dep/libc/affinity.rs b/src/tools/miri/tests/fail-dep/libc/affinity.rs
new file mode 100644
index 00000000000..c41d1d18018
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/affinity.rs
@@ -0,0 +1,17 @@
+//@ignore-target-windows: only very limited libc on Windows
+//@ignore-target-apple: `sched_setaffinity` is not supported on macOS
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4
+
+fn main() {
+    use libc::{cpu_set_t, sched_setaffinity};
+
+    use std::mem::size_of;
+
+    // If pid is zero, then the calling thread is used.
+    const PID: i32 = 0;
+
+    let cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+    let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>() + 1, &cpuset) }; //~ ERROR: memory access failed
+    assert_eq!(err, 0);
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr
new file mode 100644
index 00000000000..c01f15800fa
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds
+  --> $DIR/affinity.rs:LL:CC
+   |
+LL |     let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>() + 1, &cpuset) };
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds
+   |
+   = 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
+help: ALLOC was allocated here:
+  --> $DIR/affinity.rs:LL:CC
+   |
+LL |     let cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+   |         ^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at $DIR/affinity.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/fail-dep/libc/libc-read-and-uninit-premature-eof.rs b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
new file mode 100644
index 00000000000..98ef454c88b
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
@@ -0,0 +1,27 @@
+//! We test that if we requested to read 4 bytes, but actually read 3 bytes,
+//! then 3 bytes (not 4) will be initialized.
+//@ignore-target-windows: no file system support on Windows
+//@compile-flags: -Zmiri-disable-isolation
+
+use std::ffi::CString;
+use std::fs::remove_file;
+use std::mem::MaybeUninit;
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+
+fn main() {
+    let path =
+        utils::prepare_with_content("fail-libc-read-and-uninit-premature-eof.txt", &[1u8, 2, 3]);
+    let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap();
+    unsafe {
+        let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY);
+        assert_ne!(fd, -1);
+        let mut buf: MaybeUninit<[u8; 4]> = std::mem::MaybeUninit::uninit();
+        // Read 4 bytes from a 3-byte file.
+        assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4), 3);
+        buf.assume_init(); //~ERROR: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer
+        assert_eq!(libc::close(fd), 0);
+    }
+    remove_file(&path).unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr
new file mode 100644
index 00000000000..e4c7aba07e3
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer
+  --> $DIR/libc-read-and-uninit-premature-eof.rs:LL:CC
+   |
+LL | ...   buf.assume_init();
+   |       ^^^^^^^^^^^^^^^^^ constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer
+   |
+   = 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/libc-read-and-uninit-premature-eof.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/fail/alloc/global_system_mixup.rs b/src/tools/miri/tests/fail/alloc/global_system_mixup.rs
index 2e88e5644e4..19c62913b4c 100644
--- a/src/tools/miri/tests/fail/alloc/global_system_mixup.rs
+++ b/src/tools/miri/tests/fail/alloc/global_system_mixup.rs
@@ -4,7 +4,7 @@
 
 //@normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();"
+//@normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^}]*\};" -> "FREE();"
 
 #![feature(allocator_api, slice_ptr_get)]
 
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs
new file mode 100644
index 00000000000..023bce1616b
--- /dev/null
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs
@@ -0,0 +1,20 @@
+#![feature(raw_ref_op)]
+#![feature(strict_provenance)]
+use std::ptr;
+
+fn direct_raw(x: *const (i32, i32)) -> *const i32 {
+    unsafe { &raw const (*x).0 }
+}
+
+// Ensure that if a raw pointer is created via an intermediate
+// reference, we catch that. (Just in case someone decides to
+// desugar this differenly or so.)
+fn via_ref(x: *const (i32, i32)) -> *const i32 {
+    unsafe { &(*x).0 as *const i32 } //~ERROR: dangling pointer
+}
+
+fn main() {
+    let ptr = ptr::without_provenance(0x10);
+    direct_raw(ptr); // this is fine
+    via_ref(ptr); // this is not
+}
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr
new file mode 100644
index 00000000000..37f2bb39557
--- /dev/null
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance)
+  --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC
+   |
+LL |     unsafe { &(*x).0 as *const i32 }
+   |              ^^^^^^^ out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance)
+   |
+   = 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 `via_ref` at $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC
+note: inside `main`
+  --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC
+   |
+LL |     via_ref(ptr); // this is not
+   |     ^^^^^^^^^^^^
+
+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/concurrency/apple-os-unfair-lock.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs
new file mode 100644
index 00000000000..c2b9c37bbfb
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs
@@ -0,0 +1,25 @@
+//@ only-target-darwin
+
+use std::cell::UnsafeCell;
+
+fn main() {
+    let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
+
+    unsafe {
+        libc::os_unfair_lock_lock(lock.get());
+        libc::os_unfair_lock_assert_owner(lock.get());
+        assert!(!libc::os_unfair_lock_trylock(lock.get()));
+        libc::os_unfair_lock_unlock(lock.get());
+
+        libc::os_unfair_lock_assert_not_owner(lock.get());
+    }
+
+    // `os_unfair_lock`s can be moved and leaked.
+    // In the real implementation, even moving it while locked is possible
+    // (and "forks" the lock, i.e. old and new location have independent wait queues);
+    // Miri behavior differs here and anyway none of this is documented.
+    let lock = lock;
+    let locked = unsafe { libc::os_unfair_lock_trylock(lock.get()) };
+    assert!(locked);
+    let _lock = lock;
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
new file mode 100644
index 00000000000..0e482ab2601
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
@@ -0,0 +1,218 @@
+//@ignore-target-windows: only very limited libc on Windows
+//@ignore-target-apple: `sched_{g, s}etaffinity` are not supported on macOS
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4
+#![feature(io_error_more)]
+#![feature(pointer_is_aligned_to)]
+#![feature(strict_provenance)]
+
+use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity};
+use std::mem::{size_of, size_of_val};
+
+// If pid is zero, then the calling thread is used.
+const PID: i32 = 0;
+
+fn null_pointers() {
+    let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), std::ptr::null_mut()) };
+    assert_eq!(err, -1);
+
+    let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), std::ptr::null()) };
+    assert_eq!(err, -1);
+}
+
+fn configure_no_cpus() {
+    let cpu_count = std::thread::available_parallelism().unwrap().get();
+
+    let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+    // configuring no CPUs will fail
+    let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) };
+    assert_eq!(err, -1);
+    assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput);
+
+    // configuring no (physically available) CPUs will fail
+    unsafe { libc::CPU_SET(cpu_count, &mut cpuset) };
+    let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) };
+    assert_eq!(err, -1);
+    assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput);
+}
+
+fn configure_unavailable_cpu() {
+    let cpu_count = std::thread::available_parallelism().unwrap().get();
+
+    // Safety: valid value for this type
+    let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+    let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
+    assert_eq!(err, 0);
+
+    // by default, only available CPUs are configured
+    for i in 0..cpu_count {
+        assert!(unsafe { libc::CPU_ISSET(i, &cpuset) });
+    }
+    assert!(unsafe { !libc::CPU_ISSET(cpu_count, &cpuset) });
+
+    // configure CPU that we don't have
+    unsafe { libc::CPU_SET(cpu_count, &mut cpuset) };
+
+    let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) };
+    assert_eq!(err, 0);
+
+    let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
+    assert_eq!(err, 0);
+
+    // the CPU is not set because it is not available
+    assert!(!unsafe { libc::CPU_ISSET(cpu_count, &cpuset) });
+}
+
+fn large_set() {
+    // rust's libc does not currently implement dynamic cpu set allocation
+    // and related functions like `CPU_ZERO_S`. So we have to be creative
+
+    // i.e. this has 2048 bits, twice the standard number
+    let mut cpuset = [u64::MAX; 32];
+
+    let err = unsafe { sched_setaffinity(PID, size_of_val(&cpuset), cpuset.as_ptr().cast()) };
+    assert_eq!(err, 0);
+
+    let err = unsafe { sched_getaffinity(PID, size_of_val(&cpuset), cpuset.as_mut_ptr().cast()) };
+    assert_eq!(err, 0);
+}
+
+fn get_small_cpu_mask() {
+    let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+    // should be 4 on 32-bit systems and 8 otherwise for systems that implement sched_getaffinity
+    let step = size_of::<std::ffi::c_ulong>();
+
+    for i in (0..=2).map(|x| x * step) {
+        if i == 0 {
+            // 0 always fails
+            let err = unsafe { sched_getaffinity(PID, i, &mut cpuset) };
+            assert_eq!(err, -1, "fail for {}", i);
+            assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput);
+        } else {
+            // other whole multiples of the size of c_ulong works
+            let err = unsafe { sched_getaffinity(PID, i, &mut cpuset) };
+            assert_eq!(err, 0, "fail for {i}");
+        }
+
+        // anything else returns an error
+        for j in 1..step {
+            let err = unsafe { sched_getaffinity(PID, i + j, &mut cpuset) };
+            assert_eq!(err, -1, "success for {}", i + j);
+            assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput);
+        }
+    }
+}
+
+fn set_small_cpu_mask() {
+    let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+    let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
+    assert_eq!(err, 0);
+
+    // setting a mask of size 0 is invalid
+    let err = unsafe { sched_setaffinity(PID, 0, &cpuset) };
+    assert_eq!(err, -1);
+    assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput);
+
+    // on LE systems, any other number of bytes (at least up to `size_of<cpu_set_t>()`) will work.
+    // on BE systems the CPUs 0..8 are stored in the right-most byte of the first chunk. If that
+    // byte is not included, no valid CPUs are configured. We skip those cases.
+    let cpu_zero_included_length =
+        if cfg!(target_endian = "little") { 1 } else { core::mem::size_of::<std::ffi::c_ulong>() };
+
+    for i in cpu_zero_included_length..24 {
+        let err = unsafe { sched_setaffinity(PID, i, &cpuset) };
+        assert_eq!(err, 0, "fail for {i}");
+    }
+}
+
+fn set_custom_cpu_mask() {
+    let cpu_count = std::thread::available_parallelism().unwrap().get();
+
+    assert!(cpu_count > 1, "this test cannot do anything interesting with just one thread");
+
+    let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+    // at the start, thread 1 should be set
+    let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
+    assert_eq!(err, 0);
+    assert!(unsafe { libc::CPU_ISSET(1, &cpuset) });
+
+    // make a valid mask
+    unsafe { libc::CPU_ZERO(&mut cpuset) };
+    unsafe { libc::CPU_SET(0, &mut cpuset) };
+
+    // giving a smaller mask is fine
+    let err = unsafe { sched_setaffinity(PID, 8, &cpuset) };
+    assert_eq!(err, 0);
+
+    // and actually disables other threads
+    let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
+    assert_eq!(err, 0);
+    assert!(unsafe { !libc::CPU_ISSET(1, &cpuset) });
+
+    // it is important that we reset the cpu mask now for future tests
+    for i in 0..cpu_count {
+        unsafe { libc::CPU_SET(i, &mut cpuset) };
+    }
+
+    let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) };
+    assert_eq!(err, 0);
+}
+
+fn parent_child() {
+    let cpu_count = std::thread::available_parallelism().unwrap().get();
+
+    assert!(cpu_count > 1, "this test cannot do anything interesting with just one thread");
+
+    // configure the parent thread to only run only on CPU 0
+    let mut parent_cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+    unsafe { libc::CPU_SET(0, &mut parent_cpuset) };
+
+    let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &parent_cpuset) };
+    assert_eq!(err, 0);
+
+    std::thread::scope(|spawner| {
+        spawner.spawn(|| {
+            let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+            let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
+            assert_eq!(err, 0);
+
+            // the child inherits its parent's set
+            assert!(unsafe { libc::CPU_ISSET(0, &cpuset) });
+            assert!(unsafe { !libc::CPU_ISSET(1, &cpuset) });
+
+            // configure cpu 1 for the child
+            unsafe { libc::CPU_SET(1, &mut cpuset) };
+        });
+    });
+
+    let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut parent_cpuset) };
+    assert_eq!(err, 0);
+
+    // the parent's set should be unaffected
+    assert!(unsafe { !libc::CPU_ISSET(1, &parent_cpuset) });
+
+    // it is important that we reset the cpu mask now for future tests
+    let mut cpuset = parent_cpuset;
+    for i in 0..cpu_count {
+        unsafe { libc::CPU_SET(i, &mut cpuset) };
+    }
+
+    let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) };
+    assert_eq!(err, 0);
+}
+
+fn main() {
+    null_pointers();
+    configure_no_cpus();
+    configure_unavailable_cpu();
+    large_set();
+    get_small_cpu_mask();
+    set_small_cpu_mask();
+    set_custom_cpu_mask();
+    parent_child();
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index da685e5c6b7..eddea92353e 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -36,6 +36,7 @@ fn main() {
     #[cfg(target_os = "linux")]
     test_sync_file_range();
     test_isatty();
+    test_read_and_uninit();
 }
 
 fn test_file_open_unix_allow_two_args() {
@@ -388,3 +389,37 @@ fn test_isatty() {
         remove_file(&path).unwrap();
     }
 }
+
+fn test_read_and_uninit() {
+    use std::mem::MaybeUninit;
+    {
+        // We test that libc::read initializes its buffer.
+        let path = utils::prepare_with_content("pass-libc-read-and-uninit.txt", &[1u8, 2, 3]);
+        let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap();
+        unsafe {
+            let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY);
+            assert_ne!(fd, -1);
+            let mut buf: MaybeUninit<[u8; 2]> = std::mem::MaybeUninit::uninit();
+            assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 2), 2);
+            let buf = buf.assume_init();
+            assert_eq!(buf, [1, 2]);
+            assert_eq!(libc::close(fd), 0);
+        }
+        remove_file(&path).unwrap();
+    }
+    {
+        // We test that if we requested to read 4 bytes, but actually read 3 bytes, then
+        // 3 bytes (not 4) will be overwritten, and remaining byte will be left as-is.
+        let path = utils::prepare_with_content("pass-libc-read-and-uninit-2.txt", &[1u8, 2, 3]);
+        let cpath = CString::new(path.clone().into_os_string().into_encoded_bytes()).unwrap();
+        unsafe {
+            let fd = libc::open(cpath.as_ptr(), libc::O_RDONLY);
+            assert_ne!(fd, -1);
+            let mut buf = [42u8; 5];
+            assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4), 3);
+            assert_eq!(buf, [1, 2, 3, 42, 42]);
+            assert_eq!(libc::close(fd), 0);
+        }
+        remove_file(&path).unwrap();
+    }
+}
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 5464627fa14..6ab18a5345e 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -4,8 +4,11 @@
 #![feature(f128)]
 #![feature(f16)]
 #![allow(arithmetic_overflow)]
+#![allow(internal_features)]
 
-use std::fmt::Debug;
+use std::any::type_name;
+use std::cmp::min;
+use std::fmt::{Debug, Display, LowerHex};
 use std::hint::black_box;
 use std::{f32, f64};
 
@@ -29,15 +32,41 @@ fn main() {
     test_algebraic();
 }
 
-// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE.
-// Doesn't make a big difference when running this in Miri, but it means we can compare this
-// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`.
-#[track_caller]
-#[inline(never)]
-fn assert_eq<T: PartialEq + Debug>(x: T, y: T) {
-    assert_eq!(x, y);
+trait Float: Copy + PartialEq + Debug {
+    /// The unsigned integer with the same bit width as this float
+    type Int: Copy + PartialEq + LowerHex + Debug;
+    const BITS: u32 = size_of::<Self>() as u32 * 8;
+    const EXPONENT_BITS: u32 = Self::BITS - Self::SIGNIFICAND_BITS - 1;
+    const SIGNIFICAND_BITS: u32;
+
+    /// The saturated (all ones) value of the exponent (infinity representation)
+    const EXPONENT_SAT: u32 = (1 << Self::EXPONENT_BITS) - 1;
+
+    /// The exponent bias value (max representable positive exponent)
+    const EXPONENT_BIAS: u32 = Self::EXPONENT_SAT >> 1;
+
+    fn to_bits(self) -> Self::Int;
+}
+
+macro_rules! impl_float {
+    ($ty:ty, $ity:ty) => {
+        impl Float for $ty {
+            type Int = $ity;
+            // Just get this from std's value, which includes the implicit digit
+            const SIGNIFICAND_BITS: u32 = <$ty>::MANTISSA_DIGITS - 1;
+
+            fn to_bits(self) -> Self::Int {
+                self.to_bits()
+            }
+        }
+    };
 }
 
+impl_float!(f16, u16);
+impl_float!(f32, u32);
+impl_float!(f64, u64);
+impl_float!(f128, u128);
+
 trait FloatToInt<Int>: Copy {
     fn cast(self) -> Int;
     unsafe fn cast_unchecked(self) -> Int;
@@ -58,19 +87,61 @@ macro_rules! float_to_int {
     };
 }
 
+float_to_int!(f16 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
 float_to_int!(f32 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
 float_to_int!(f64 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
+float_to_int!(f128 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
 
 /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate).
 #[track_caller]
 #[inline(never)]
-fn test_both_cast<F, I>(x: F, y: I)
+fn test_both_cast<F, I>(x: F, y: I, msg: impl Display)
 where
     F: FloatToInt<I>,
     I: PartialEq + Debug,
 {
-    assert_eq!(x.cast(), y);
-    assert_eq!(unsafe { x.cast_unchecked() }, y);
+    let f_tname = type_name::<F>();
+    let i_tname = type_name::<I>();
+    assert_eq!(x.cast(), y, "{f_tname} -> {i_tname}: {msg}");
+    assert_eq!(unsafe { x.cast_unchecked() }, y, "{f_tname} -> {i_tname}: {msg}",);
+}
+
+/// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE.
+/// Doesn't make a big difference when running this in Miri, but it means we can compare this
+/// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`.
+#[track_caller]
+#[inline(never)]
+fn assert_eq<T: PartialEq + Debug>(x: T, y: T) {
+    assert_eq!(x, y);
+}
+
+/// The same as `assert_eq` except prints a specific message on failure
+#[track_caller]
+#[inline(never)]
+fn assert_eq_msg<T: PartialEq + Debug>(x: T, y: T, msg: impl Display) {
+    assert_eq!(x, y, "{msg}");
+}
+
+/// Check that floats have bitwise equality
+fn assert_biteq<F: Float>(a: F, b: F, msg: impl Display) {
+    let ab = a.to_bits();
+    let bb = b.to_bits();
+    let tname = type_name::<F>();
+    let width = (2 + F::BITS / 4) as usize;
+    assert_eq_msg::<F::Int>(
+        ab,
+        bb,
+        format_args!("({ab:#0width$x} != {bb:#0width$x}) {tname}: {msg}"),
+    );
+}
+
+/// Check that two floats have equality
+fn assert_feq<F: Float>(a: F, b: F, msg: impl Display) {
+    let ab = a.to_bits();
+    let bb = b.to_bits();
+    let tname = type_name::<F>();
+    let width = (2 + F::BITS / 4) as usize;
+    assert_eq_msg::<F>(a, b, format_args!("({ab:#0width$x} != {bb:#0width$x}) {tname}: {msg}"));
 }
 
 fn basic() {
@@ -148,155 +219,368 @@ fn basic() {
     assert_eq!(34.2f64.abs(), 34.2f64);
 }
 
-/// Many of these test values are taken from
+/// Test casts from floats to ints and back
+macro_rules! test_ftoi_itof {
+    (
+        f: $fty:ty,
+        i: $ity:ty,
+        // Int min and max as float literals
+        imin_f: $imin_f:literal,
+        imax_f: $imax_f:literal $(,)?
+    ) => {{
+        /// By default we test float to int `as` casting as well as to_int_unchecked
+        fn assert_ftoi(f: $fty, i: $ity, msg: &str) {
+            #[allow(unused_comparisons)]
+            if <$ity>::MIN >= 0 && f < 0.0 {
+                // If `ity` is signed and `f` is negative, it is unrepresentable so skip
+                // unchecked casts.
+                assert_ftoi_unrep(f, i, msg);
+            } else {
+                test_both_cast::<$fty, $ity>(f, i, msg);
+            }
+        }
+
+        /// Unrepresentable values only get tested with `as` casting, not unchecked
+        fn assert_ftoi_unrep(f: $fty, i: $ity, msg: &str) {
+            assert_eq_msg::<$ity>(
+                f as $ity,
+                i,
+                format_args!("{} -> {}: {msg}", stringify!($fty), stringify!($ity)),
+            );
+        }
+
+        /// Int to float checks
+        fn assert_itof(i: $ity, f: $fty, msg: &str) {
+            assert_eq_msg::<$fty>(
+                i as $fty,
+                f,
+                format_args!("{} -> {}: {msg}", stringify!($ity), stringify!($fty)),
+            );
+        }
+
+        /// Check both float to int and int to float
+        fn assert_bidir(f: $fty, i: $ity, msg: &str) {
+            assert_ftoi(f, i, msg);
+            assert_itof(i, f, msg);
+        }
+
+        /// Check both float to int and int to float for unrepresentable numbers
+        fn assert_bidir_unrep(f: $fty, i: $ity, msg: &str) {
+            assert_ftoi_unrep(f, i, msg);
+            assert_itof(i, f, msg);
+        }
+
+        let fbits = <$fty>::BITS;
+        let fsig_bits = <$fty>::SIGNIFICAND_BITS;
+        let ibits = <$ity>::BITS;
+        let imax: $ity = <$ity>::MAX;
+        let imin: $ity = <$ity>::MIN;
+        let izero: $ity = 0;
+        #[allow(unused_comparisons)]
+        let isigned = <$ity>::MIN < 0;
+
+        #[allow(overflowing_literals)]
+        let imin_f: $fty = $imin_f;
+        #[allow(overflowing_literals)]
+        let imax_f: $fty = $imax_f;
+
+        // If an integer can fit entirely in the mantissa (counting the hidden bit), every value
+        // can be represented exactly.
+        let all_ints_exact_rep = ibits <= fsig_bits + 1;
+
+        // We can represent the full range of the integer (but possibly not every value) without
+        // saturating to infinity if `1 << (I::BITS - 1)` (single one in the MSB position) is
+        // within the float's dynamic range.
+        let int_range_rep = ibits - 1 < <$fty>::EXPONENT_BIAS;
+
+        // Skip unchecked cast when int min/max would be unrepresentable
+        let assert_ftoi_big = if all_ints_exact_rep { assert_ftoi } else { assert_ftoi_unrep };
+        let assert_bidir_big = if all_ints_exact_rep { assert_bidir } else { assert_bidir_unrep };
+
+        // Near zero representations
+        assert_bidir(0.0, 0, "zero");
+        assert_ftoi(-0.0, 0, "negative zero");
+        assert_ftoi(1.0, 1, "one");
+        assert_ftoi(-1.0, izero.saturating_sub(1), "negative one");
+        assert_ftoi(1.0 - <$fty>::EPSILON, 0, "1.0 - ε");
+        assert_ftoi(1.0 + <$fty>::EPSILON, 1, "1.0 + ε");
+        assert_ftoi(-1.0 + <$fty>::EPSILON, 0, "-1.0 + ε");
+        assert_ftoi(-1.0 - <$fty>::EPSILON, izero.saturating_sub(1), "-1.0 - ε");
+        assert_ftoi(<$fty>::from_bits(0x1), 0, "min subnormal");
+        assert_ftoi(<$fty>::from_bits(0x1 | 1 << (fbits - 1)), 0, "min neg subnormal");
+
+        // Spot checks. Use `saturating_sub` to create negative integers so that unsigned
+        // integers stay at zero.
+        assert_ftoi(0.9, 0, "0.9");
+        assert_ftoi(-0.9, 0, "-0.9");
+        assert_ftoi(1.1, 1, "1.1");
+        assert_ftoi(-1.1, izero.saturating_sub(1), "-1.1");
+        assert_ftoi(1.9, 1, "1.9");
+        assert_ftoi(-1.9, izero.saturating_sub(1), "-1.9");
+        assert_ftoi(5.0, 5, "5.0");
+        assert_ftoi(-5.0, izero.saturating_sub(5), "-5.0");
+        assert_ftoi(5.9, 5, "5.0");
+        assert_ftoi(-5.9, izero.saturating_sub(5), "-5.0");
+
+        // Exercise the middle of the integer's bit range. A power of two fits as long as the
+        // exponent can fit its log2, so cap at the maximum representable power of two (which
+        // is the exponent's bias).
+        let half_i_max: $ity = 1 << min(ibits / 2, <$fty>::EXPONENT_BIAS);
+        let half_i_min = izero.saturating_sub(half_i_max);
+        assert_bidir(half_i_max as $fty, half_i_max, "half int max");
+        assert_bidir(half_i_min as $fty, half_i_min, "half int min");
+
+        // Integer limits
+        assert_bidir_big(imax_f, imax, "i max");
+        assert_bidir_big(imin_f, imin, "i min");
+
+        // We need a small perturbation to test against that does not round up to the next
+        // integer. `f16` needs a smaller perturbation since it only has resolution for ~1 decimal
+        // place near 10^3.
+        let perturb = if fbits < 32 { 0.9 } else { 0.99 };
+        assert_ftoi_big(imax_f + perturb, <$ity>::MAX, "slightly above i max");
+        assert_ftoi_big(imin_f - perturb, <$ity>::MIN, "slightly below i min");
+
+        // Tests for when we can represent the integer's magnitude
+        if int_range_rep {
+            // If the float can represent values larger than the integer, float extremes
+            // will saturate.
+            assert_ftoi_unrep(<$fty>::MAX, imax, "f max");
+            assert_ftoi_unrep(<$fty>::MIN, imin, "f min");
+
+            // Max representable power of 10
+            let pow10_max = (10 as $ity).pow(imax.ilog10());
+
+            // If the power of 10 should be representable (fits in a mantissa), check it
+            if ibits - pow10_max.leading_zeros() - pow10_max.trailing_zeros() <= fsig_bits + 1 {
+                assert_bidir(pow10_max as $fty, pow10_max, "pow10 max");
+            }
+        }
+
+        // Test rounding the largest and smallest integers, but skip this when
+        // all integers have an exact representation (it's less interesting then and the arithmetic gets more complicated).
+        if int_range_rep && !all_ints_exact_rep {
+            // The maximum representable integer is a saturated mantissa (including the implicit
+            // bit), shifted into the int's leftmost position.
+            //
+            // Positive signed integers never use their top bit, so shift by one bit fewer.
+            let sat_mantissa: $ity = (1 << (fsig_bits + 1)) - 1;
+            let adj = if isigned { 1 } else { 0 };
+            let max_rep = sat_mantissa << (sat_mantissa.leading_zeros() - adj);
+
+            // This value should roundtrip exactly
+            assert_bidir(max_rep as $fty, max_rep, "max representable int");
+
+            // The cutoff for where to round to `imax` is halfway between the maximum exactly
+            // representable integer and `imax`. This should round down (to `max_rep`),
+            // i.e., `max_rep as $fty == max_non_sat as $fty`.
+            let max_non_sat = max_rep + ((imax - max_rep) / 2);
+            assert_bidir(max_non_sat as $fty, max_rep, "max non saturating int");
+
+            // So the next value up should round up to the maximum value of the integer
+            assert_bidir_unrep((max_non_sat + 1) as $fty, imax, "min infinite int");
+
+            if isigned {
+                // Floats can always represent the minimum signed number if they can fit the
+                // exponent, because it is just a `1` in the MSB. So, no negative int -> float
+                // conversion will round to negative infinity (if the exponent fits).
+                //
+                // Since `imin` is thus the minimum representable value, we test rounding near
+                // the next value. This happens to be the opposite of the maximum representable
+                // value, and it should roundtrip exactly.
+                let next_min_rep = max_rep.wrapping_neg();
+                assert_bidir(next_min_rep as $fty, next_min_rep, "min representable above imin");
+
+                // Following a similar pattern as for positive numbers, halfway between this value
+                // and `imin` should round back to `next_min_rep`.
+                let min_non_sat = imin - ((imin - next_min_rep) / 2) + 1;
+                assert_bidir(
+                    min_non_sat as $fty,
+                    next_min_rep,
+                    "min int that does not round to imin",
+                );
+
+                // And then anything else saturates to the minimum value.
+                assert_bidir_unrep(
+                    (min_non_sat - 1) as $fty,
+                    imin,
+                    "max negative int that rounds to imin",
+                );
+            }
+        }
+
+        // Check potentially saturating int ranges. (`imax_f` here will be `$fty::INFINITY` if
+        // it cannot be represented as a finite value.)
+        assert_itof(imax, imax_f, "imax");
+        assert_itof(imin, imin_f, "imin");
+
+        // Float limits
+        assert_ftoi_unrep(<$fty>::INFINITY, imax, "f inf");
+        assert_ftoi_unrep(<$fty>::NEG_INFINITY, imin, "f neg inf");
+        assert_ftoi_unrep(<$fty>::NAN, 0, "f nan");
+        assert_ftoi_unrep(-<$fty>::NAN, 0, "f neg nan");
+    }};
+}
+
+/// Test casts from one float to another
+macro_rules! test_ftof {
+    (
+        f1: $f1:ty,
+        f2: $f2:ty $(,)?
+    ) => {{
+        type F2Int = <$f2 as Float>::Int;
+
+        let f1zero: $f1 = 0.0;
+        let f2zero: $f2 = 0.0;
+        let f1five: $f1 = 5.0;
+        let f2five: $f2 = 5.0;
+
+        assert_biteq((f1zero as $f2), f2zero, "0.0");
+        assert_biteq(((-f1zero) as $f2), (-f2zero), "-0.0");
+        assert_biteq((f1five as $f2), f2five, "5.0");
+        assert_biteq(((-f1five) as $f2), (-f2five), "-5.0");
+
+        assert_feq(<$f1>::INFINITY as $f2, <$f2>::INFINITY, "max -> inf");
+        assert_feq(<$f1>::NEG_INFINITY as $f2, <$f2>::NEG_INFINITY, "max -> inf");
+        assert!((<$f1>::NAN as $f2).is_nan(), "{} -> {} nan", stringify!($f1), stringify!($f2));
+
+        let min_sub_casted = <$f1>::from_bits(0x1) as $f2;
+        let min_neg_sub_casted = <$f1>::from_bits(0x1 | 1 << (<$f1>::BITS - 1)) as $f2;
+
+        if <$f1>::BITS > <$f2>::BITS {
+            assert_feq(<$f1>::MAX as $f2, <$f2>::INFINITY, "max -> inf");
+            assert_feq(<$f1>::MIN as $f2, <$f2>::NEG_INFINITY, "max -> inf");
+            assert_biteq(min_sub_casted, f2zero, "min subnormal -> 0.0");
+            assert_biteq(min_neg_sub_casted, -f2zero, "min neg subnormal -> -0.0");
+        } else {
+            // When increasing precision, the minimum subnormal will just roll to the next
+            // exponent. This exponent will be the current exponent (with bias), plus
+            // `sig_bits - 1` to account for the implicit change in exponent (since the
+            // mantissa starts with 0).
+            let sub_casted = <$f2>::from_bits(
+                ((<$f2>::EXPONENT_BIAS - (<$f1>::EXPONENT_BIAS + <$f1>::SIGNIFICAND_BITS - 1))
+                    as F2Int)
+                    << <$f2>::SIGNIFICAND_BITS,
+            );
+            assert_biteq(min_sub_casted, sub_casted, "min subnormal");
+            assert_biteq(min_neg_sub_casted, -sub_casted, "min neg subnormal");
+        }
+    }};
+}
+
+/// Many of these test patterns were adapted from the values in
 /// https://github.com/WebAssembly/testsuite/blob/master/conversions.wast.
 fn casts() {
-    // f32 -> i8
-    test_both_cast::<f32, i8>(127.99, 127);
-    test_both_cast::<f32, i8>(-128.99, -128);
-
-    // f32 -> i32
-    test_both_cast::<f32, i32>(0.0, 0);
-    test_both_cast::<f32, i32>(-0.0, 0);
-    test_both_cast::<f32, i32>(/*0x1p-149*/ f32::from_bits(0x00000001), 0);
-    test_both_cast::<f32, i32>(/*-0x1p-149*/ f32::from_bits(0x80000001), 0);
-    test_both_cast::<f32, i32>(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1);
-    test_both_cast::<f32, i32>(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1);
-    test_both_cast::<f32, i32>(1.9, 1);
-    test_both_cast::<f32, i32>(-1.9, -1);
-    test_both_cast::<f32, i32>(5.0, 5);
-    test_both_cast::<f32, i32>(-5.0, -5);
-    test_both_cast::<f32, i32>(2147483520.0, 2147483520);
-    test_both_cast::<f32, i32>(-2147483648.0, -2147483648);
-    // unrepresentable casts
-    assert_eq::<i32>(2147483648.0f32 as i32, i32::MAX);
-    assert_eq::<i32>(-2147483904.0f32 as i32, i32::MIN);
-    assert_eq::<i32>(f32::MAX as i32, i32::MAX);
-    assert_eq::<i32>(f32::MIN as i32, i32::MIN);
-    assert_eq::<i32>(f32::INFINITY as i32, i32::MAX);
-    assert_eq::<i32>(f32::NEG_INFINITY as i32, i32::MIN);
-    assert_eq::<i32>(f32::NAN as i32, 0);
-    assert_eq::<i32>((-f32::NAN) as i32, 0);
-
-    // f32 -> u32
-    test_both_cast::<f32, u32>(0.0, 0);
-    test_both_cast::<f32, u32>(-0.0, 0);
-    test_both_cast::<f32, u32>(-0.9999999, 0);
-    test_both_cast::<f32, u32>(/*0x1p-149*/ f32::from_bits(0x1), 0);
-    test_both_cast::<f32, u32>(/*-0x1p-149*/ f32::from_bits(0x80000001), 0);
-    test_both_cast::<f32, u32>(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1);
-    test_both_cast::<f32, u32>(1.9, 1);
-    test_both_cast::<f32, u32>(5.0, 5);
-    test_both_cast::<f32, u32>(2147483648.0, 0x8000_0000);
-    test_both_cast::<f32, u32>(4294967040.0, 0u32.wrapping_sub(256));
-    test_both_cast::<f32, u32>(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0);
-    test_both_cast::<f32, u32>(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0);
-    test_both_cast::<f32, u32>((u32::MAX - 128) as f32, u32::MAX - 255); // rounding loss
-    // unrepresentable casts
-    assert_eq::<u32>((u32::MAX - 127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable
-    assert_eq::<u32>(4294967296.0f32 as u32, u32::MAX);
-    assert_eq::<u32>(-5.0f32 as u32, 0);
-    assert_eq::<u32>(f32::MAX as u32, u32::MAX);
-    assert_eq::<u32>(f32::MIN as u32, 0);
-    assert_eq::<u32>(f32::INFINITY as u32, u32::MAX);
-    assert_eq::<u32>(f32::NEG_INFINITY as u32, 0);
-    assert_eq::<u32>(f32::NAN as u32, 0);
-    assert_eq::<u32>((-f32::NAN) as u32, 0);
-
-    // f32 -> i64
-    test_both_cast::<f32, i64>(4294967296.0, 4294967296);
-    test_both_cast::<f32, i64>(-4294967296.0, -4294967296);
-    test_both_cast::<f32, i64>(9223371487098961920.0, 9223371487098961920);
-    test_both_cast::<f32, i64>(-9223372036854775808.0, -9223372036854775808);
-
-    // f64 -> i8
-    test_both_cast::<f64, i8>(127.99, 127);
-    test_both_cast::<f64, i8>(-128.99, -128);
-
-    // f64 -> i32
-    test_both_cast::<f64, i32>(0.0, 0);
-    test_both_cast::<f64, i32>(-0.0, 0);
-    test_both_cast::<f64, i32>(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1);
-    test_both_cast::<f64, i32>(
-        /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a),
-        -1,
-    );
-    test_both_cast::<f64, i32>(1.9, 1);
-    test_both_cast::<f64, i32>(-1.9, -1);
-    test_both_cast::<f64, i32>(1e8, 100_000_000);
-    test_both_cast::<f64, i32>(2147483647.0, 2147483647);
-    test_both_cast::<f64, i32>(-2147483648.0, -2147483648);
-    // unrepresentable casts
-    assert_eq::<i32>(2147483648.0f64 as i32, i32::MAX);
-    assert_eq::<i32>(-2147483649.0f64 as i32, i32::MIN);
-
-    // f64 -> i64
-    test_both_cast::<f64, i64>(0.0, 0);
-    test_both_cast::<f64, i64>(-0.0, 0);
-    test_both_cast::<f64, i64>(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0);
-    test_both_cast::<f64, i64>(
-        /*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001),
-        0,
-    );
-    test_both_cast::<f64, i64>(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1);
-    test_both_cast::<f64, i64>(
-        /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a),
-        -1,
-    );
-    test_both_cast::<f64, i64>(5.0, 5);
-    test_both_cast::<f64, i64>(5.9, 5);
-    test_both_cast::<f64, i64>(-5.0, -5);
-    test_both_cast::<f64, i64>(-5.9, -5);
-    test_both_cast::<f64, i64>(4294967296.0, 4294967296);
-    test_both_cast::<f64, i64>(-4294967296.0, -4294967296);
-    test_both_cast::<f64, i64>(9223372036854774784.0, 9223372036854774784);
-    test_both_cast::<f64, i64>(-9223372036854775808.0, -9223372036854775808);
-    // unrepresentable casts
-    assert_eq::<i64>(9223372036854775808.0f64 as i64, i64::MAX);
-    assert_eq::<i64>(-9223372036854777856.0f64 as i64, i64::MIN);
-    assert_eq::<i64>(f64::MAX as i64, i64::MAX);
-    assert_eq::<i64>(f64::MIN as i64, i64::MIN);
-    assert_eq::<i64>(f64::INFINITY as i64, i64::MAX);
-    assert_eq::<i64>(f64::NEG_INFINITY as i64, i64::MIN);
-    assert_eq::<i64>(f64::NAN as i64, 0);
-    assert_eq::<i64>((-f64::NAN) as i64, 0);
-
-    // f64 -> u64
-    test_both_cast::<f64, u64>(0.0, 0);
-    test_both_cast::<f64, u64>(-0.0, 0);
-    test_both_cast::<f64, u64>(-0.99999999999, 0);
-    test_both_cast::<f64, u64>(5.0, 5);
-    test_both_cast::<f64, u64>(1e16, 10000000000000000);
-    test_both_cast::<f64, u64>((u64::MAX - 1024) as f64, u64::MAX - 2047); // rounding loss
-    test_both_cast::<f64, u64>(9223372036854775808.0, 9223372036854775808);
-    // unrepresentable casts
-    assert_eq::<u64>(-5.0f64 as u64, 0);
-    assert_eq::<u64>((u64::MAX - 1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable
-    assert_eq::<u64>(18446744073709551616.0f64 as u64, u64::MAX);
-    assert_eq::<u64>(f64::MAX as u64, u64::MAX);
-    assert_eq::<u64>(f64::MIN as u64, 0);
-    assert_eq::<u64>(f64::INFINITY as u64, u64::MAX);
-    assert_eq::<u64>(f64::NEG_INFINITY as u64, 0);
-    assert_eq::<u64>(f64::NAN as u64, 0);
-    assert_eq::<u64>((-f64::NAN) as u64, 0);
-
-    // f64 -> i128
-    assert_eq::<i128>(f64::MAX as i128, i128::MAX);
-    assert_eq::<i128>(f64::MIN as i128, i128::MIN);
-
-    // f64 -> u128
-    assert_eq::<u128>(f64::MAX as u128, u128::MAX);
-    assert_eq::<u128>(f64::MIN as u128, 0);
+    /* int <-> float generic tests */
+
+    test_ftoi_itof! { f: f16, i: i8, imin_f: -128.0, imax_f: 127.0 };
+    test_ftoi_itof! { f: f16, i: u8, imin_f: 0.0, imax_f: 255.0 };
+    test_ftoi_itof! { f: f16, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 };
+    test_ftoi_itof! { f: f16, i: u16, imin_f: 0.0, imax_f: 65_535.0 };
+    test_ftoi_itof! { f: f16, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 };
+    test_ftoi_itof! { f: f16, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 };
+    test_ftoi_itof! {
+        f: f16,
+        i: i64,
+        imin_f: -9_223_372_036_854_775_808.0,
+        imax_f: 9_223_372_036_854_775_807.0
+    };
+    test_ftoi_itof! { f: f16, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 };
+    test_ftoi_itof! {
+        f: f16,
+        i: i128,
+        imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0,
+        imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0,
+    };
+    test_ftoi_itof! {
+        f: f16,
+        i: u128,
+        imin_f: 0.0,
+        imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0
+    };
+
+    test_ftoi_itof! { f: f32, i: i8, imin_f: -128.0, imax_f: 127.0 };
+    test_ftoi_itof! { f: f32, i: u8, imin_f: 0.0, imax_f: 255.0 };
+    test_ftoi_itof! { f: f32, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 };
+    test_ftoi_itof! { f: f32, i: u16, imin_f: 0.0, imax_f: 65_535.0 };
+    test_ftoi_itof! { f: f32, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 };
+    test_ftoi_itof! { f: f32, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 };
+    test_ftoi_itof! {
+        f: f32,
+        i: i64,
+        imin_f: -9_223_372_036_854_775_808.0,
+        imax_f: 9_223_372_036_854_775_807.0
+    };
+    test_ftoi_itof! { f: f32, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 };
+    test_ftoi_itof! {
+        f: f32,
+        i: i128,
+        imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0,
+        imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0,
+    };
+    test_ftoi_itof! {
+        f: f32,
+        i: u128,
+        imin_f: 0.0,
+        imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0
+    };
+
+    test_ftoi_itof! { f: f64, i: i8, imin_f: -128.0, imax_f: 127.0 };
+    test_ftoi_itof! { f: f64, i: u8, imin_f: 0.0, imax_f: 255.0 };
+    test_ftoi_itof! { f: f64, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 };
+    test_ftoi_itof! { f: f64, i: u16, imin_f: 0.0, imax_f: 65_535.0 };
+    test_ftoi_itof! { f: f64, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 };
+    test_ftoi_itof! { f: f64, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 };
+    test_ftoi_itof! {
+        f: f64,
+        i: i64,
+        imin_f: -9_223_372_036_854_775_808.0,
+        imax_f: 9_223_372_036_854_775_807.0
+    };
+    test_ftoi_itof! { f: f64, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 };
+    test_ftoi_itof! {
+        f: f64,
+        i: i128,
+        imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0,
+        imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0,
+    };
+    test_ftoi_itof! {
+        f: f64,
+        i: u128,
+        imin_f: 0.0,
+        imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0
+    };
+
+    test_ftoi_itof! { f: f128, i: i8, imin_f: -128.0, imax_f: 127.0 };
+    test_ftoi_itof! { f: f128, i: u8, imin_f: 0.0, imax_f: 255.0 };
+    test_ftoi_itof! { f: f128, i: i16, imin_f: -32_768.0, imax_f: 32_767.0 };
+    test_ftoi_itof! { f: f128, i: u16, imin_f: 0.0, imax_f: 65_535.0 };
+    test_ftoi_itof! { f: f128, i: i32, imin_f: -2_147_483_648.0, imax_f: 2_147_483_647.0 };
+    test_ftoi_itof! { f: f128, i: u32, imin_f: 0.0, imax_f: 4_294_967_295.0 };
+    test_ftoi_itof! {
+        f: f128,
+        i: i64,
+        imin_f: -9_223_372_036_854_775_808.0,
+        imax_f: 9_223_372_036_854_775_807.0
+    };
+    test_ftoi_itof! { f: f128, i: u64, imin_f: 0.0, imax_f: 18_446_744_073_709_551_615.0 };
+    test_ftoi_itof! {
+        f: f128,
+        i: i128,
+        imin_f: -170_141_183_460_469_231_731_687_303_715_884_105_728.0,
+        imax_f: 170_141_183_460_469_231_731_687_303_715_884_105_727.0,
+    };
+    test_ftoi_itof! {
+        f: f128,
+        i: u128,
+        imin_f: 0.0,
+        imax_f: 340_282_366_920_938_463_463_374_607_431_768_211_455.0
+    };
+
+    /* int <-> float spot checks */
 
     // int -> f32
-    assert_eq::<f32>(127i8 as f32, 127.0);
-    assert_eq::<f32>(2147483647i32 as f32, 2147483648.0);
-    assert_eq::<f32>((-2147483648i32) as f32, -2147483648.0);
     assert_eq::<f32>(1234567890i32 as f32, /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06));
-    assert_eq::<f32>(16777217i32 as f32, 16777216.0);
-    assert_eq::<f32>((-16777217i32) as f32, -16777216.0);
-    assert_eq::<f32>(16777219i32 as f32, 16777220.0);
-    assert_eq::<f32>((-16777219i32) as f32, -16777220.0);
     assert_eq::<f32>(
         0x7fffff4000000001i64 as f32,
         /*0x1.fffffep+62*/ f32::from_bits(0x5effffff),
@@ -313,36 +597,33 @@ fn casts() {
         0xffdfffffdfffffffu64 as i64 as f32,
         /*-0x1.000002p+53*/ f32::from_bits(0xda000001),
     );
-    assert_eq::<f32>(i128::MIN as f32, -170141183460469231731687303715884105728.0f32);
-    assert_eq::<f32>(u128::MAX as f32, f32::INFINITY); // saturation
 
     // int -> f64
-    assert_eq::<f64>(127i8 as f64, 127.0);
-    assert_eq::<f64>(i16::MIN as f64, -32768.0f64);
-    assert_eq::<f64>(2147483647i32 as f64, 2147483647.0);
-    assert_eq::<f64>(-2147483648i32 as f64, -2147483648.0);
     assert_eq::<f64>(987654321i32 as f64, 987654321.0);
-    assert_eq::<f64>(9223372036854775807i64 as f64, 9223372036854775807.0);
-    assert_eq::<f64>(-9223372036854775808i64 as f64, -9223372036854775808.0);
     assert_eq::<f64>(4669201609102990i64 as f64, 4669201609102990.0); // Feigenbaum (?)
     assert_eq::<f64>(9007199254740993i64 as f64, 9007199254740992.0);
     assert_eq::<f64>(-9007199254740993i64 as f64, -9007199254740992.0);
     assert_eq::<f64>(9007199254740995i64 as f64, 9007199254740996.0);
     assert_eq::<f64>(-9007199254740995i64 as f64, -9007199254740996.0);
-    assert_eq::<f64>(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits...
+
+    /* float -> float generic tests */
+
+    test_ftof! { f1: f16, f2: f32 };
+    test_ftof! { f1: f16, f2: f64 };
+    test_ftof! { f1: f16, f2: f128 };
+    test_ftof! { f1: f32, f2: f16 };
+    test_ftof! { f1: f32, f2: f64 };
+    test_ftof! { f1: f32, f2: f128 };
+    test_ftof! { f1: f64, f2: f16 };
+    test_ftof! { f1: f64, f2: f32 };
+    test_ftof! { f1: f64, f2: f128 };
+    test_ftof! { f1: f128, f2: f16 };
+    test_ftof! { f1: f128, f2: f32 };
+    test_ftof! { f1: f128, f2: f64 };
+
+    /* float -> float spot checks */
 
     // f32 -> f64
-    assert_eq::<u64>((0.0f32 as f64).to_bits(), 0.0f64.to_bits());
-    assert_eq::<u64>(((-0.0f32) as f64).to_bits(), (-0.0f64).to_bits());
-    assert_eq::<f64>(5.0f32 as f64, 5.0f64);
-    assert_eq::<f64>(
-        /*0x1p-149*/ f32::from_bits(0x1) as f64,
-        /*0x1p-149*/ f64::from_bits(0x36a0000000000000),
-    );
-    assert_eq::<f64>(
-        /*-0x1p-149*/ f32::from_bits(0x80000001) as f64,
-        /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000),
-    );
     assert_eq::<f64>(
         /*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64,
         /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000),
@@ -359,15 +640,8 @@ fn casts() {
         /*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64,
         6.6382536710104395e+37,
     );
-    assert_eq::<f64>(f32::INFINITY as f64, f64::INFINITY);
-    assert_eq::<f64>(f32::NEG_INFINITY as f64, f64::NEG_INFINITY);
 
     // f64 -> f32
-    assert_eq::<u32>((0.0f64 as f32).to_bits(), 0.0f32.to_bits());
-    assert_eq::<u32>(((-0.0f64) as f32).to_bits(), (-0.0f32).to_bits());
-    assert_eq::<f32>(5.0f64 as f32, 5.0f32);
-    assert_eq::<f32>(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0);
-    assert_eq::<f32>(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0);
     assert_eq::<f32>(
         /*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32,
         /*0x1p-149*/ f32::from_bits(0x800000),
@@ -376,10 +650,6 @@ fn casts() {
         /*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32,
         /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728),
     );
-    assert_eq::<f32>(f64::MAX as f32, f32::INFINITY);
-    assert_eq::<f32>(f64::MIN as f32, f32::NEG_INFINITY);
-    assert_eq::<f32>(f64::INFINITY as f32, f32::INFINITY);
-    assert_eq::<f32>(f64::NEG_INFINITY as f32, f32::NEG_INFINITY);
 }
 
 fn ops() {
diff --git a/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs
new file mode 100644
index 00000000000..845f50c1eba
--- /dev/null
+++ b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.rs
@@ -0,0 +1,43 @@
+//@only-target-darwin
+
+use std::thread;
+
+extern "C" {
+    fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
+}
+
+fn register<F>(f: F)
+where
+    F: FnOnce() + 'static,
+{
+    // This will receive the pointer passed into `_tlv_atexit`, which is the
+    // original `f` but boxed up.
+    unsafe extern "C" fn run<F>(ptr: *mut u8)
+    where
+        F: FnOnce() + 'static,
+    {
+        let f = unsafe { Box::from_raw(ptr as *mut F) };
+        f()
+    }
+
+    unsafe {
+        _tlv_atexit(run::<F>, Box::into_raw(Box::new(f)) as *mut u8);
+    }
+}
+
+fn main() {
+    thread::spawn(|| {
+        register(|| println!("dtor 2"));
+        register(|| println!("dtor 1"));
+        println!("exiting thread");
+    })
+    .join()
+    .unwrap();
+
+    println!("exiting main");
+    register(|| println!("dtor 5"));
+    register(|| {
+        println!("registering dtor in dtor 3");
+        register(|| println!("dtor 4"));
+    });
+}
diff --git a/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout
new file mode 100644
index 00000000000..89d6ca25935
--- /dev/null
+++ b/src/tools/miri/tests/pass/tls/macos_tlv_atexit.stdout
@@ -0,0 +1,7 @@
+exiting thread
+dtor 1
+dtor 2
+exiting main
+registering dtor in dtor 3
+dtor 4
+dtor 5
diff --git a/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs b/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs
index 2d142bef73c..a3356b682a6 100644
--- a/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs
+++ b/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs
@@ -39,8 +39,6 @@ fn test_ptr(ptr: *mut ()) {
         // Distance.
         let ptr = ptr.cast::<i32>();
         ptr.offset_from(ptr);
-        /*
-        FIXME: this is disabled for now as these cases are not yet allowed.
         // Distance from other "bad" pointers that have the same address, but different provenance. Some
         // of this is library UB, but we don't want it to be language UB since that would violate
         // provenance monotonicity: if we allow computing the distance between two ptrs with no
@@ -54,6 +52,5 @@ fn test_ptr(ptr: *mut ()) {
         // - Distance from use-after-free pointer
         drop(b);
         ptr.offset_from(other_ptr.with_addr(ptr.addr()));
-        */
     }
 }
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index ec3b8a96ef3..969552dec84 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -11,3 +11,5 @@ wasmparser = "0.118.2"
 regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
 gimli = "0.28.1"
 ar = "0.9.0"
+
+build_helper = { path = "../build_helper" }
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index c506c3d6b61..5017a4b88da 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -5,8 +5,8 @@ use std::panic;
 use std::path::Path;
 use std::process::{Command as StdCommand, ExitStatus, Output, Stdio};
 
-use crate::drop_bomb::DropBomb;
 use crate::{assert_contains, assert_equals, assert_not_contains, handle_failed_output};
+use build_helper::drop_bomb::DropBomb;
 
 /// This is a custom command wrapper that simplifies working with commands and makes it easier to
 /// ensure that we check the exit status of executed processes.
diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs
index 24fa88af82e..ad989b74e4d 100644
--- a/src/tools/run-make-support/src/diff/mod.rs
+++ b/src/tools/run-make-support/src/diff/mod.rs
@@ -2,8 +2,8 @@ use regex::Regex;
 use similar::TextDiff;
 use std::path::{Path, PathBuf};
 
-use crate::drop_bomb::DropBomb;
 use crate::fs_wrapper;
+use build_helper::drop_bomb::DropBomb;
 
 #[cfg(test)]
 mod tests;
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 5655318267a..e5f1ce1bf34 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -7,7 +7,6 @@ pub mod cc;
 pub mod clang;
 mod command;
 pub mod diff;
-mod drop_bomb;
 pub mod fs_wrapper;
 pub mod llvm;
 pub mod run;
@@ -303,6 +302,11 @@ pub fn filename_not_in_denylist<P: AsRef<Path>, V: AsRef<[String]>>(path: P, exp
         .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned()))
 }
 
+/// Returns true if the filename at `path` ends with `suffix`.
+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))
+}
+
 /// Gathers all files in the current working directory that have the extension `ext`, and counts
 /// the number of lines within that contain a match with the regex pattern `re`.
 pub fn count_regex_matches_in_files_with_extension(re: &regex::Regex, ext: &str) -> usize {
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index a2a7c8064dc..ae200d51431 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -4,13 +4,15 @@ use std::path::Path;
 
 use crate::{command, cwd, env_var, set_host_rpath};
 
-/// Construct a new `rustc` invocation.
+/// Construct a new `rustc` invocation. This will automatically set the library
+/// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this.
 #[track_caller]
 pub fn rustc() -> Rustc {
     Rustc::new()
 }
 
-/// Construct a plain `rustc` invocation with no flags set.
+/// Construct a plain `rustc` invocation with no flags set. Note that [`set_host_rpath`]
+/// still presets the environment variable `HOST_RPATH_DIR` by default.
 #[track_caller]
 pub fn bare_rustc() -> Rustc {
     Rustc::bare()
@@ -42,7 +44,8 @@ fn setup_common() -> Command {
 impl Rustc {
     // `rustc` invocation constructor methods
 
-    /// Construct a new `rustc` invocation.
+    /// Construct a new `rustc` invocation. This will automatically set the library
+    /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this.
     #[track_caller]
     pub fn new() -> Self {
         let mut cmd = setup_common();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 01e43a67e43..bf2ff1a917c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -4,11 +4,10 @@ use std::fmt;
 
 use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
 use once_cell::unsync::Lazy;
-use rustc_index::IndexVec;
 use rustc_pattern_analysis::{
     constructor::{Constructor, ConstructorSet, VariantVisibility},
     usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport},
-    Captures, PatCx, PrivateUninhabitedField,
+    Captures, IndexVec, PatCx, PrivateUninhabitedField,
 };
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
@@ -53,7 +52,7 @@ impl EnumVariantContiguousIndex {
     }
 }
 
-impl rustc_index::Idx for EnumVariantContiguousIndex {
+impl rustc_pattern_analysis::Idx for EnumVariantContiguousIndex {
     fn new(idx: usize) -> Self {
         EnumVariantContiguousIndex(idx)
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs
index 1e829299e6f..2ff967416c0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/version.rs
@@ -15,7 +15,7 @@ pub struct VersionInfo {
     pub version: &'static str,
     /// The release channel we were built for (stable/beta/nightly/dev).
     ///
-    /// `None` if not built via rustbuild.
+    /// `None` if not built via bootstrap.
     pub release_channel: Option<&'static str>,
     /// Information about the Git repository we may have been built from.
     ///
diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs
index c211b34850a..e7020980dc3 100644
--- a/src/tools/rust-installer/src/combiner.rs
+++ b/src/tools/rust-installer/src/combiner.rs
@@ -109,7 +109,7 @@ impl Combiner {
                 .with_context(|| format!("failed to read components in '{}'", input_tarball))?;
             for component in pkg_components.split_whitespace() {
                 // All we need to do is copy the component directory. We could
-                // move it, but rustbuild wants to reuse the unpacked package
+                // move it, but bootstrap wants to reuse the unpacked package
                 // dir for OS-specific installers on macOS and Windows.
                 let component_dir = package_dir.join(component);
                 create_dir(&component_dir)?;
diff --git a/src/tools/rust-installer/test.sh b/src/tools/rust-installer/test.sh
index 16b05c66197..7b3e7456006 100755
--- a/src/tools/rust-installer/test.sh
+++ b/src/tools/rust-installer/test.sh
@@ -974,7 +974,7 @@ combined_remains() {
     --package-name=rust \
     --input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz"
     for component in rustc cargo rust-docs; do
-    # rustbuild wants the original extracted package intact too
+    # bootstrap wants the original extracted package intact too
     try test -d "$WORK_DIR/$component/$component"
     try test -d "$WORK_DIR/rust/$component"
     done
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 33120cf93f9..f7ec7d0b3f6 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -23,7 +23,6 @@ run-make/dep-info/Makefile
 run-make/dump-ice-to-disk/Makefile
 run-make/dump-mono-stats/Makefile
 run-make/emit-to-stdout/Makefile
-run-make/env-dep-info/Makefile
 run-make/export-executable-symbols/Makefile
 run-make/extern-diff-internal-name/Makefile
 run-make/extern-flag-disambiguates/Makefile
@@ -37,7 +36,6 @@ run-make/extern-fn-with-packed-struct/Makefile
 run-make/extern-fn-with-union/Makefile
 run-make/extern-multiple-copies/Makefile
 run-make/extern-multiple-copies2/Makefile
-run-make/extra-filename-with-temp-outputs/Makefile
 run-make/fmt-write-bloat/Makefile
 run-make/foreign-double-unwind/Makefile
 run-make/foreign-exceptions/Makefile
@@ -58,9 +56,7 @@ run-make/issue-35164/Makefile
 run-make/issue-36710/Makefile
 run-make/issue-47551/Makefile
 run-make/issue-69368/Makefile
-run-make/issue-83045/Makefile
 run-make/issue-84395-lto-embed-bitcode/Makefile
-run-make/issue-85019-moved-src-dir/Makefile
 run-make/issue-85401-static-mir/Makefile
 run-make/issue-88756-default-output/Makefile
 run-make/issue-97463-abi-param-passing/Makefile
@@ -116,7 +112,6 @@ run-make/return-non-c-like-enum-from-c/Makefile
 run-make/rlib-format-packed-bundled-libs-2/Makefile
 run-make/rlib-format-packed-bundled-libs-3/Makefile
 run-make/rlib-format-packed-bundled-libs/Makefile
-run-make/rustc-macro-dep-files/Makefile
 run-make/sanitizer-cdylib-link/Makefile
 run-make/sanitizer-dylib-link/Makefile
 run-make/sanitizer-staticlib-link/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 82fa43f581f..3c72fae0881 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -353,6 +353,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "rustc-hash",
     "rustc-rayon",
     "rustc-rayon-core",
+    "rustc-stable-hash",
     "rustc_apfloat",
     "rustc_version",
     "rustix",
diff --git a/tests/assembly/x86-return-float.rs b/tests/assembly/x86-return-float.rs
new file mode 100644
index 00000000000..c4a2c1ad44e
--- /dev/null
+++ b/tests/assembly/x86-return-float.rs
@@ -0,0 +1,328 @@
+//@ assembly-output: emit-asm
+//@ only-x86
+// FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled.
+// There's no compiletest directive to ignore a test on i586 only, so just always explicitly enable
+// SSE2.
+// Use the same target CPU as `i686` so that LLVM orders the instructions in the same order.
+//@ compile-flags: -Ctarget-feature=+sse2 -Ctarget-cpu=pentium4
+// 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
+
+#![crate_type = "lib"]
+#![feature(f16, f128)]
+
+// Tests that returning `f32` and `f64` with the "Rust" ABI on 32-bit x86 doesn't use the x87
+// floating point stack, as loading and storing `f32`s and `f64`s to and from the x87 stack quietens
+// signalling NaNs.
+
+// Returning individual floats
+
+// CHECK-LABEL: return_f32:
+#[no_mangle]
+pub fn return_f32(x: f32) -> f32 {
+    // CHECK: movl {{.*}}(%ebp), %eax
+    // CHECK-NOT: ax
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_f64:
+#[no_mangle]
+pub fn return_f64(x: f64) -> f64 {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL:.*]]
+    // CHECK-NEXT: movsd %[[VAL]], (%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// Returning scalar pairs containing floats
+
+// CHECK-LABEL: return_f32_f32:
+#[no_mangle]
+pub fn return_f32_f32(x: (f32, f32)) -> (f32, f32) {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_f64_f64:
+#[no_mangle]
+pub fn return_f64_f64(x: (f64, f64)) -> (f64, f64) {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movsd [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_f32_f64:
+#[no_mangle]
+pub fn return_f32_f64(x: (f32, f64)) -> (f32, f64) {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_f64_f32:
+#[no_mangle]
+pub fn return_f64_f32(x: (f64, f32)) -> (f64, f32) {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movss [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_f32_other:
+#[no_mangle]
+pub fn return_f32_other(x: (f32, usize)) -> (f32, usize) {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_f64_other:
+#[no_mangle]
+pub fn return_f64_other(x: (f64, usize)) -> (f64, usize) {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_other_f32:
+#[no_mangle]
+pub fn return_other_f32(x: (usize, f32)) -> (usize, f32) {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_other_f64:
+#[no_mangle]
+pub fn return_other_f64(x: (usize, f64)) -> (usize, f64) {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movsd %[[VAL2]], {{4|8}}(%[[PTR]])
+    // CHECK: retl
+    x
+}
+
+// Calling functions returning floats
+
+// CHECK-LABEL: call_f32:
+#[no_mangle]
+pub unsafe fn call_f32(x: &mut f32) {
+    extern "Rust" {
+        fn get_f32() -> f32;
+    }
+    // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
+    // CHECK: calll {{()|_}}get_f32
+    // CHECK-NEXT: movl %eax, (%[[PTR]])
+    *x = get_f32();
+}
+
+// CHECK-LABEL: call_f64:
+#[no_mangle]
+pub unsafe fn call_f64(x: &mut f64) {
+    extern "Rust" {
+        fn get_f64() -> f64;
+    }
+    // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
+    // CHECK: calll {{()|_}}get_f64
+    // CHECK: movsd {{.*}}(%{{ebp|esp}}), %[[VAL:.*]]
+    // CHECK-NEXT: movsd %[[VAL:.*]], (%[[PTR]])
+    *x = get_f64();
+}
+
+// Calling functions returning scalar pairs containing floats
+
+// CHECK-LABEL: call_f32_f32:
+#[no_mangle]
+pub unsafe fn call_f32_f32(x: &mut (f32, f32)) {
+    extern "Rust" {
+        fn get_f32_f32() -> (f32, f32);
+    }
+    // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
+    // CHECK: calll {{()|_}}get_f32_f32
+    // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]])
+    *x = get_f32_f32();
+}
+
+// CHECK-LABEL: call_f64_f64:
+#[no_mangle]
+pub unsafe fn call_f64_f64(x: &mut (f64, f64)) {
+    extern "Rust" {
+        fn get_f64_f64() -> (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:.*]]
+    // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
+    *x = get_f64_f64();
+}
+
+// CHECK-LABEL: call_f32_f64:
+#[no_mangle]
+pub unsafe fn call_f32_f64(x: &mut (f32, f64)) {
+    extern "Rust" {
+        fn get_f32_f64() -> (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:.*]]
+    // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]])
+    // unix-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
+    // windows-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
+    *x = get_f32_f64();
+}
+
+// CHECK-LABEL: call_f64_f32:
+#[no_mangle]
+pub unsafe fn call_f64_f32(x: &mut (f64, f32)) {
+    extern "Rust" {
+        fn get_f64_f32() -> (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:.*]]
+    // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movss %[[VAL2]], 8(%[[PTR]])
+    *x = get_f64_f32();
+}
+
+// CHECK-LABEL: call_f32_other:
+#[no_mangle]
+pub unsafe fn call_f32_other(x: &mut (f32, usize)) {
+    extern "Rust" {
+        fn get_f32_other() -> (f32, usize);
+    }
+    // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
+    // CHECK: calll {{()|_}}get_f32_other
+    // CHECK: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movss %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movl %[[VAL2]], 4(%[[PTR]])
+    *x = get_f32_other();
+}
+
+// CHECK-LABEL: call_f64_other:
+#[no_mangle]
+pub unsafe fn call_f64_other(x: &mut (f64, usize)) {
+    extern "Rust" {
+        fn get_f64_other() -> (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:.*]]
+    // CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movl %[[VAL2]], 8(%[[PTR]])
+    *x = get_f64_other();
+}
+
+// CHECK-LABEL: call_other_f32:
+#[no_mangle]
+pub unsafe fn call_other_f32(x: &mut (usize, f32)) {
+    extern "Rust" {
+        fn get_other_f32() -> (usize, f32);
+    }
+    // CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
+    // CHECK: calll {{()|_}}get_other_f32
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movss [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]])
+    // CHECK-NEXT: movss %[[VAL2]], 4(%[[PTR]])
+    *x = get_other_f32();
+}
+
+// CHECK-LABEL: call_other_f64:
+#[no_mangle]
+pub unsafe fn call_other_f64(x: &mut (usize, f64)) {
+    extern "Rust" {
+        fn get_other_f64() -> (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:.*]]
+    // CHECK-NEXT: movl %[[VAL1]], (%[[PTR]])
+    // unix-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
+    // windows-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
+    *x = get_other_f64();
+}
+
+// The "C" ABI for `f16` and `f128` on x86 has never used the x87 floating point stack. Do some
+// basic checks to ensure this remains the case for the "Rust" ABI.
+
+// CHECK-LABEL: return_f16:
+#[no_mangle]
+pub fn return_f16(x: f16) -> f16 {
+    // CHECK: pinsrw $0, {{.*}}(%ebp), %xmm0
+    // CHECK-NOT: xmm0
+    // CHECK: retl
+    x
+}
+
+// CHECK-LABEL: return_f128:
+#[no_mangle]
+pub fn return_f128(x: f128) -> f128 {
+    // CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+16]](%ebp), %[[VAL4:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
+    // CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL3:.*]]
+    // CHECK-NEXT: movl %[[VAL4:.*]] 12(%[[PTR]])
+    // CHECK-NEXT: movl %[[VAL3:.*]] 8(%[[PTR]])
+    // CHECK-NEXT: movl %[[VAL2:.*]] 4(%[[PTR]])
+    // CHECK-NEXT: movl %[[VAL1:.*]] (%[[PTR]])
+    // CHECK: retl
+    x
+}
diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs
index 32c5be1ec65..80b572fbbc9 100644
--- a/tests/codegen/float/f128.rs
+++ b/tests/codegen/float/f128.rs
@@ -1,3 +1,8 @@
+// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack.
+//@ revisions: x86 other
+//@[x86] only-x86
+//@[other] ignore-x86
+
 // Verify that our intrinsics generate the correct LLVM calls for f128
 
 #![crate_type = "lib"]
@@ -138,14 +143,16 @@ pub fn f128_as_f16(a: f128) -> f16 {
     a as f16
 }
 
-// CHECK-LABEL: float @f128_as_f32(
+// other-LABEL: float @f128_as_f32(
+// x86-LABEL: i32 @f128_as_f32(
 #[no_mangle]
 pub fn f128_as_f32(a: f128) -> f32 {
     // CHECK: fptrunc fp128 %{{.+}} to float
     a as f32
 }
 
-// CHECK-LABEL: double @f128_as_f64(
+// other-LABEL: double @f128_as_f64(
+// x86-LABEL: void @f128_as_f64(
 #[no_mangle]
 pub fn f128_as_f64(a: f128) -> f64 {
     // CHECK: fptrunc fp128 %{{.+}} to double
diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs
index 96daac869c2..2910d7d3e92 100644
--- a/tests/codegen/float/f16.rs
+++ b/tests/codegen/float/f16.rs
@@ -1,3 +1,8 @@
+// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack.
+//@ revisions: x86 other
+//@[x86] only-x86
+//@[other] ignore-x86
+
 // Verify that our intrinsics generate the correct LLVM calls for f16
 
 #![crate_type = "lib"]
@@ -140,14 +145,16 @@ pub fn f16_as_self(a: f16) -> f16 {
     a as f16
 }
 
-// CHECK-LABEL: float @f16_as_f32(
+// other-LABEL: float @f16_as_f32(
+// x86-LABEL: i32 @f16_as_f32(
 #[no_mangle]
 pub fn f16_as_f32(a: f16) -> f32 {
     // CHECK: fpext half %{{.+}} to float
     a as f32
 }
 
-// CHECK-LABEL: double @f16_as_f64(
+// other-LABEL: double @f16_as_f64(
+// x86-LABEL: void @f16_as_f64(
 #[no_mangle]
 pub fn f16_as_f64(a: f16) -> f64 {
     // CHECK: fpext half %{{.+}} to double
diff --git a/tests/codegen/issues/issue-32031.rs b/tests/codegen/issues/issue-32031.rs
index 9693c414a67..4d6895166f1 100644
--- a/tests/codegen/issues/issue-32031.rs
+++ b/tests/codegen/issues/issue-32031.rs
@@ -1,11 +1,16 @@
 //@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+// 32-bit x86 returns `f32` and `f64` differently to avoid the x87 stack.
+//@ revisions: x86 other
+//@[x86] only-x86
+//@[other] ignore-x86
 
 #![crate_type = "lib"]
 
 #[no_mangle]
 pub struct F32(f32);
 
-// CHECK: define{{.*}}float @add_newtype_f32(float %a, float %b)
+// other: define{{.*}}float @add_newtype_f32(float %a, float %b)
+// x86: define{{.*}}i32 @add_newtype_f32(float %a, float %b)
 #[inline(never)]
 #[no_mangle]
 pub fn add_newtype_f32(a: F32, b: F32) -> F32 {
@@ -15,7 +20,8 @@ pub fn add_newtype_f32(a: F32, b: F32) -> F32 {
 #[no_mangle]
 pub struct F64(f64);
 
-// CHECK: define{{.*}}double @add_newtype_f64(double %a, double %b)
+// other: define{{.*}}double @add_newtype_f64(double %a, double %b)
+// x86: define{{.*}}void @add_newtype_f64(ptr{{.*}}sret([8 x i8]){{.*}}%_0, double %a, double %b)
 #[inline(never)]
 #[no_mangle]
 pub fn add_newtype_f64(a: F64, b: F64) -> F64 {
diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs
index 9e02fa9ff35..08015014456 100644
--- a/tests/codegen/union-abi.rs
+++ b/tests/codegen/union-abi.rs
@@ -1,5 +1,9 @@
 //@ ignore-emscripten vectors passed directly
 //@ compile-flags: -O -C no-prepopulate-passes
+// 32-bit x86 returns `f32` differently to avoid the x87 stack.
+//@ revisions: x86 other
+//@[x86] only-x86
+//@[other] ignore-x86
 
 // This test that using union forward the abi of the inner type, as
 // discussed in #54668
@@ -67,7 +71,8 @@ pub union UnionF32 {
     a: f32,
 }
 
-// CHECK: define {{(dso_local )?}}float @test_UnionF32(float %_1)
+// other: define {{(dso_local )?}}float @test_UnionF32(float %_1)
+// x86: define {{(dso_local )?}}i32 @test_UnionF32(float %_1)
 #[no_mangle]
 pub fn test_UnionF32(_: UnionF32) -> UnionF32 {
     loop {}
@@ -78,7 +83,8 @@ pub union UnionF32F32 {
     b: f32,
 }
 
-// CHECK: define {{(dso_local )?}}float @test_UnionF32F32(float %_1)
+// other: define {{(dso_local )?}}float @test_UnionF32F32(float %_1)
+// x86: define {{(dso_local )?}}i32 @test_UnionF32F32(float %_1)
 #[no_mangle]
 pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 {
     loop {}
diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map
index f36ef7af7ac..6edd35921fe 100644
--- a/tests/coverage/closure.cov-map
+++ b/tests/coverage/closure.cov-map
@@ -31,16 +31,18 @@ Number of file 0 mappings: 24
     = (c0 - c1)
 - Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2)
 
-Function name: closure::main::{closure#0} (unused)
-Raw bytes (24): 0x[01, 01, 00, 04, 00, 28, 05, 02, 14, 00, 02, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06]
+Function name: closure::main::{closure#0}
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 0
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 Number of file 0 mappings: 4
-- Code(Zero) at (prev + 40, 5) to (start + 2, 20)
-- Code(Zero) at (prev + 2, 21) to (start + 2, 10)
-- Code(Zero) at (prev + 2, 10) to (start + 0, 11)
-- Code(Zero) at (prev + 1, 9) to (start + 1, 6)
+- Code(Counter(0)) at (prev + 40, 5) to (start + 2, 20)
+- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10)
+- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11)
+    = (c0 - c1)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6)
 
 Function name: closure::main::{closure#10} (unused)
 Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21]
diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map
index 9c18827d8e6..11a99f5395e 100644
--- a/tests/coverage/try_error_result.cov-map
+++ b/tests/coverage/try_error_result.cov-map
@@ -81,101 +81,130 @@ Number of file 0 mappings: 11
     = (((c4 + Zero) + Zero) + c3)
 
 Function name: try_error_result::test2
-Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02]
+Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, c7, 01, db, 01, cb, 01, cf, 01, 11, 15, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 36
+Number of expressions: 59
 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add)
-- expression 1 operands: lhs = Zero, rhs = Counter(2)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(16), rhs = Zero
-- expression 4 operands: lhs = Expression(7, Sub), rhs = Zero
-- expression 5 operands: lhs = Counter(16), rhs = Zero
-- expression 6 operands: lhs = Expression(7, Sub), rhs = Zero
-- expression 7 operands: lhs = Counter(16), rhs = Zero
-- expression 8 operands: lhs = Expression(18, Sub), rhs = Zero
-- expression 9 operands: lhs = Expression(19, Sub), rhs = Zero
-- expression 10 operands: lhs = Expression(20, Sub), rhs = Counter(16)
-- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Expression(20, Sub), rhs = Counter(16)
-- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 14 operands: lhs = Expression(19, Sub), rhs = Zero
-- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(16)
-- expression 16 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 17 operands: lhs = Expression(18, Sub), rhs = Zero
-- expression 18 operands: lhs = Expression(19, Sub), rhs = Zero
-- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(16)
-- expression 20 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 21 operands: lhs = Expression(25, Sub), rhs = Zero
-- expression 22 operands: lhs = Counter(17), rhs = Zero
-- expression 23 operands: lhs = Counter(17), rhs = Zero
-- expression 24 operands: lhs = Expression(25, Sub), rhs = Zero
-- expression 25 operands: lhs = Counter(17), rhs = Zero
-- expression 26 operands: lhs = Expression(30, Sub), rhs = Zero
-- expression 27 operands: lhs = Counter(19), rhs = Zero
-- expression 28 operands: lhs = Counter(19), rhs = Zero
-- expression 29 operands: lhs = Expression(30, Sub), rhs = Zero
-- expression 30 operands: lhs = Counter(19), rhs = Zero
-- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(3)
-- expression 32 operands: lhs = Expression(33, Add), rhs = Zero
-- expression 33 operands: lhs = Zero, rhs = Expression(34, Add)
-- expression 34 operands: lhs = Expression(35, Add), rhs = Zero
-- expression 35 operands: lhs = Counter(6), rhs = Zero
+- expression 3 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 5 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 6 operands: lhs = Expression(16, Sub), rhs = Counter(7)
+- expression 7 operands: lhs = Expression(17, Sub), rhs = Counter(6)
+- expression 8 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 9 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 10 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 11 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 12 operands: lhs = Expression(17, Sub), rhs = Counter(6)
+- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 14 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(7)
+- expression 16 operands: lhs = Expression(17, Sub), rhs = Counter(6)
+- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 18 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 19 operands: lhs = Expression(23, Sub), rhs = Counter(9)
+- expression 20 operands: lhs = Counter(18), rhs = Counter(8)
+- expression 21 operands: lhs = Counter(18), rhs = Counter(8)
+- expression 22 operands: lhs = Expression(23, Sub), rhs = Counter(9)
+- expression 23 operands: lhs = Counter(18), rhs = Counter(8)
+- expression 24 operands: lhs = Expression(34, Sub), rhs = Counter(11)
+- expression 25 operands: lhs = Expression(35, Sub), rhs = Counter(10)
+- expression 26 operands: lhs = Expression(36, Sub), rhs = Counter(16)
+- expression 27 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 28 operands: lhs = Expression(36, Sub), rhs = Counter(16)
+- expression 29 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 30 operands: lhs = Expression(35, Sub), rhs = Counter(10)
+- expression 31 operands: lhs = Expression(36, Sub), rhs = Counter(16)
+- expression 32 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 33 operands: lhs = Expression(34, Sub), rhs = Counter(11)
+- expression 34 operands: lhs = Expression(35, Sub), rhs = Counter(10)
+- expression 35 operands: lhs = Expression(36, Sub), rhs = Counter(16)
+- expression 36 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 37 operands: lhs = Expression(41, Sub), rhs = Counter(13)
+- expression 38 operands: lhs = Counter(17), rhs = Counter(12)
+- expression 39 operands: lhs = Counter(17), rhs = Counter(12)
+- expression 40 operands: lhs = Expression(41, Sub), rhs = Counter(13)
+- expression 41 operands: lhs = Counter(17), rhs = Counter(12)
+- expression 42 operands: lhs = Expression(46, Sub), rhs = Counter(15)
+- expression 43 operands: lhs = Counter(19), rhs = Counter(14)
+- expression 44 operands: lhs = Counter(19), rhs = Counter(14)
+- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(15)
+- expression 46 operands: lhs = Counter(19), rhs = Counter(14)
+- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(3)
+- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(54, Add)
+- expression 49 operands: lhs = Expression(50, Add), rhs = Expression(51, Add)
+- expression 50 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
+- expression 52 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 53 operands: lhs = Counter(8), rhs = Counter(9)
+- expression 54 operands: lhs = Expression(55, Add), rhs = Expression(56, Add)
+- expression 55 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 56 operands: lhs = Expression(57, Add), rhs = Expression(58, Add)
+- expression 57 operands: lhs = Counter(12), rhs = Counter(13)
+- expression 58 operands: lhs = Counter(14), rhs = Counter(15)
 Number of file 0 mappings: 40
 - Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23)
 - Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14)
-    = (c0 + (Zero + c2))
-- Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 4, 26)
-    = ((c0 + (Zero + c2)) - c3)
+    = (c0 + (c1 + c2))
+- Code(Expression(36, Sub)) at (prev + 2, 9) to (start + 4, 26)
+    = ((c0 + (c1 + c2)) - c3)
 - Code(Counter(16)) at (prev + 6, 13) to (start + 0, 47)
-- Code(Zero) at (prev + 0, 47) to (start + 0, 48)
-- Code(Expression(7, Sub)) at (prev + 0, 49) to (start + 3, 53)
-    = (c16 - Zero)
-- Code(Zero) at (prev + 4, 17) to (start + 0, 18)
-- Code(Expression(6, Sub)) at (prev + 2, 17) to (start + 4, 18)
-    = ((c16 - Zero) - Zero)
-- Code(Zero) at (prev + 5, 17) to (start + 0, 20)
-- Code(Expression(6, Sub)) at (prev + 0, 23) to (start + 0, 65)
-    = ((c16 - Zero) - Zero)
+- Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48)
+- Code(Expression(18, Sub)) at (prev + 0, 49) to (start + 3, 53)
+    = (c16 - c4)
+- Code(Counter(5)) at (prev + 4, 17) to (start + 0, 18)
+- Code(Expression(17, Sub)) at (prev + 2, 17) to (start + 4, 18)
+    = ((c16 - c4) - c5)
+- Code(Expression(15, Sub)) at (prev + 5, 17) to (start + 0, 20)
+    = ((((c16 - c4) - c5) - c6) - c7)
+- Code(Expression(17, Sub)) at (prev + 0, 23) to (start + 0, 65)
+    = ((c16 - c4) - c5)
 - Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66)
-- Code(Zero) at (prev + 0, 67) to (start + 0, 95)
-- Code(Zero) at (prev + 0, 95) to (start + 0, 96)
-- Code(Zero) at (prev + 1, 13) to (start + 0, 32)
-- Code(Zero) at (prev + 1, 17) to (start + 0, 20)
-- Code(Zero) at (prev + 0, 23) to (start + 0, 65)
-- Code(Zero) at (prev + 0, 65) to (start + 0, 66)
-- Code(Zero) at (prev + 0, 67) to (start + 0, 96)
-- Code(Zero) at (prev + 0, 96) to (start + 0, 97)
-- Code(Zero) at (prev + 1, 13) to (start + 0, 32)
-- Code(Expression(17, Sub)) at (prev + 4, 17) to (start + 0, 20)
-    = (((((c0 + (Zero + c2)) - c3) - c16) - Zero) - Zero)
-- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 66)
-    = (((c0 + (Zero + c2)) - c3) - c16)
-- Code(Zero) at (prev + 0, 66) to (start + 0, 67)
-- Code(Expression(18, Sub)) at (prev + 0, 68) to (start + 0, 97)
-    = ((((c0 + (Zero + c2)) - c3) - c16) - Zero)
-- Code(Zero) at (prev + 0, 97) to (start + 0, 98)
-- Code(Expression(17, Sub)) at (prev + 1, 13) to (start + 0, 32)
-    = (((((c0 + (Zero + c2)) - c3) - c16) - Zero) - Zero)
-- Code(Expression(24, Sub)) at (prev + 1, 17) to (start + 0, 20)
-    = ((c17 - Zero) - Zero)
+- Code(Expression(16, Sub)) at (prev + 0, 67) to (start + 0, 95)
+    = (((c16 - c4) - c5) - c6)
+- Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96)
+- Code(Expression(15, Sub)) at (prev + 1, 13) to (start + 0, 32)
+    = ((((c16 - c4) - c5) - c6) - c7)
+- Code(Expression(22, Sub)) at (prev + 1, 17) to (start + 0, 20)
+    = ((c18 - c8) - c9)
+- Code(Counter(18)) at (prev + 0, 23) to (start + 0, 65)
+- Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66)
+- Code(Expression(23, Sub)) at (prev + 0, 67) to (start + 0, 96)
+    = (c18 - c8)
+- Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97)
+- Code(Expression(22, Sub)) at (prev + 1, 13) to (start + 0, 32)
+    = ((c18 - c8) - c9)
+- Code(Expression(33, Sub)) at (prev + 4, 17) to (start + 0, 20)
+    = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11)
+- Code(Expression(35, Sub)) at (prev + 0, 23) to (start + 0, 66)
+    = (((c0 + (c1 + c2)) - c3) - c16)
+- Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67)
+- Code(Expression(34, Sub)) at (prev + 0, 68) to (start + 0, 97)
+    = ((((c0 + (c1 + c2)) - c3) - c16) - c10)
+- Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98)
+- Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 32)
+    = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11)
+- Code(Expression(40, Sub)) at (prev + 1, 17) to (start + 0, 20)
+    = ((c17 - c12) - c13)
 - Code(Counter(17)) at (prev + 0, 23) to (start + 1, 54)
-- Code(Zero) at (prev + 1, 54) to (start + 0, 55)
-- Code(Expression(25, Sub)) at (prev + 1, 18) to (start + 0, 47)
-    = (c17 - Zero)
-- Code(Zero) at (prev + 0, 47) to (start + 0, 48)
-- Code(Expression(24, Sub)) at (prev + 1, 13) to (start + 0, 32)
-    = ((c17 - Zero) - Zero)
-- Code(Expression(29, Sub)) at (prev + 1, 17) to (start + 0, 20)
-    = ((c19 - Zero) - Zero)
+- Code(Counter(12)) at (prev + 1, 54) to (start + 0, 55)
+- Code(Expression(41, Sub)) at (prev + 1, 18) to (start + 0, 47)
+    = (c17 - c12)
+- Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48)
+- Code(Expression(40, Sub)) at (prev + 1, 13) to (start + 0, 32)
+    = ((c17 - c12) - c13)
+- Code(Expression(45, Sub)) at (prev + 1, 17) to (start + 0, 20)
+    = ((c19 - c14) - c15)
 - Code(Counter(19)) at (prev + 0, 23) to (start + 1, 54)
-- Code(Zero) at (prev + 2, 17) to (start + 0, 18)
-- Code(Expression(30, Sub)) at (prev + 1, 18) to (start + 0, 47)
-    = (c19 - Zero)
-- Code(Zero) at (prev + 1, 17) to (start + 0, 18)
-- Code(Expression(29, Sub)) at (prev + 2, 13) to (start + 0, 32)
-    = ((c19 - Zero) - Zero)
+- Code(Counter(14)) at (prev + 2, 17) to (start + 0, 18)
+- Code(Expression(46, Sub)) at (prev + 1, 18) to (start + 0, 47)
+    = (c19 - c14)
+- Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18)
+- Code(Expression(45, Sub)) at (prev + 2, 13) to (start + 0, 32)
+    = ((c19 - c14) - c15)
 - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11)
-- Code(Expression(31, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (((Zero + ((c6 + Zero) + Zero)) + Zero) + c3)
+- Code(Expression(47, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = ((((c4 + c5) + ((c6 + c7) + (c8 + c9))) + ((c10 + c11) + ((c12 + c13) + (c14 + c15)))) + c3)
 
diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs
deleted file mode 100644
index 9b6c5169d44..00000000000
--- a/tests/crashes/126416.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ known-bug: rust-lang/rust#126416
-
-trait Output<'a, T: 'a> {
-    type Type;
-}
-
-struct Wrapper;
-
-impl Wrapper {
-    fn do_something_wrapper<O, F>(&mut self, _: F)
-    where
-        F: for<'a> FnOnce(<F as Output<i32>>::Type),
-    {
-    }
-}
-
-fn main() {
-    let mut wrapper = Wrapper;
-    wrapper.do_something_wrapper(|value| ());
-}
diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir
index bade0fa4b45..9ebfff18f48 100644
--- a/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir
+++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir
@@ -62,7 +62,7 @@ fn full_tested_match() -> () {
         _6 = &((_2 as Some).0: i32);
         _3 = &fake shallow _2;
         StorageLive(_7);
-        _7 = guard() -> [return: bb8, unwind: bb16];
+        _7 = guard() -> [return: bb8, unwind: bb15];
     }
 
     bb8: {
@@ -118,11 +118,7 @@ fn full_tested_match() -> () {
         unreachable;
     }
 
-    bb15: {
-        goto -> bb14;
-    }
-
-    bb16 (cleanup): {
+    bb15 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir
index 0d78bb8b235..4d2989ea93e 100644
--- a/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir
+++ b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir
@@ -68,7 +68,7 @@ fn full_tested_match2() -> () {
         _6 = &((_2 as Some).0: i32);
         _3 = &fake shallow _2;
         StorageLive(_7);
-        _7 = guard() -> [return: bb8, unwind: bb16];
+        _7 = guard() -> [return: bb8, unwind: bb15];
     }
 
     bb8: {
@@ -118,11 +118,7 @@ fn full_tested_match2() -> () {
         unreachable;
     }
 
-    bb15: {
-        goto -> bb14;
-    }
-
-    bb16 (cleanup): {
+    bb15 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
index ebb75ae141a..4ed93610706 100644
--- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
+++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir
@@ -38,65 +38,61 @@ fn main() -> () {
         StorageLive(_2);
         _2 = Option::<i32>::Some(const 1_i32);
         PlaceMention(_2);
-        _5 = discriminant(_2);
-        switchInt(move _5) -> [1: bb8, otherwise: bb2];
+        _4 = discriminant(_2);
+        switchInt(move _4) -> [1: bb2, otherwise: bb1];
     }
 
     bb1: {
-        FakeRead(ForMatchedPlace(None), _2);
-        unreachable;
+        falseEdge -> [real: bb14, imaginary: bb4];
     }
 
     bb2: {
-        falseEdge -> [real: bb15, imaginary: bb3];
+        falseEdge -> [real: bb9, imaginary: bb1];
     }
 
     bb3: {
-        _4 = discriminant(_2);
-        switchInt(move _4) -> [1: bb6, otherwise: bb4];
+        goto -> bb1;
     }
 
     bb4: {
+        _5 = discriminant(_2);
+        switchInt(move _5) -> [1: bb6, otherwise: bb5];
+    }
+
+    bb5: {
         StorageLive(_14);
         _14 = _2;
         _1 = const 4_i32;
         StorageDead(_14);
-        goto -> bb21;
-    }
-
-    bb5: {
-        goto -> bb1;
+        goto -> bb20;
     }
 
     bb6: {
-        falseEdge -> [real: bb16, imaginary: bb4];
+        falseEdge -> [real: bb15, imaginary: bb5];
     }
 
     bb7: {
-        goto -> bb4;
+        goto -> bb5;
     }
 
     bb8: {
-        falseEdge -> [real: bb10, imaginary: bb2];
+        FakeRead(ForMatchedPlace(None), _2);
+        unreachable;
     }
 
     bb9: {
-        goto -> bb2;
-    }
-
-    bb10: {
         StorageLive(_7);
         _7 = &((_2 as Some).0: i32);
         _3 = &fake shallow _2;
         StorageLive(_8);
-        _8 = guard() -> [return: bb11, unwind: bb24];
+        _8 = guard() -> [return: bb10, unwind: bb22];
     }
 
-    bb11: {
-        switchInt(move _8) -> [0: bb13, otherwise: bb12];
+    bb10: {
+        switchInt(move _8) -> [0: bb12, otherwise: bb11];
     }
 
-    bb12: {
+    bb11: {
         StorageDead(_8);
         FakeRead(ForMatchGuard, _3);
         FakeRead(ForGuardBinding, _7);
@@ -105,42 +101,42 @@ fn main() -> () {
         _1 = const 1_i32;
         StorageDead(_6);
         StorageDead(_7);
-        goto -> bb21;
+        goto -> bb20;
     }
 
-    bb13: {
-        goto -> bb14;
+    bb12: {
+        goto -> bb13;
     }
 
-    bb14: {
+    bb13: {
         StorageDead(_8);
         StorageDead(_7);
-        falseEdge -> [real: bb9, imaginary: bb2];
+        falseEdge -> [real: bb3, imaginary: bb1];
     }
 
-    bb15: {
+    bb14: {
         StorageLive(_9);
         _9 = _2;
         _1 = const 2_i32;
         StorageDead(_9);
-        goto -> bb21;
+        goto -> bb20;
     }
 
-    bb16: {
+    bb15: {
         StorageLive(_11);
         _11 = &((_2 as Some).0: i32);
         _3 = &fake shallow _2;
         StorageLive(_12);
         StorageLive(_13);
         _13 = (*_11);
-        _12 = guard2(move _13) -> [return: bb17, unwind: bb24];
+        _12 = guard2(move _13) -> [return: bb16, unwind: bb22];
     }
 
-    bb17: {
-        switchInt(move _12) -> [0: bb19, otherwise: bb18];
+    bb16: {
+        switchInt(move _12) -> [0: bb18, otherwise: bb17];
     }
 
-    bb18: {
+    bb17: {
         StorageDead(_13);
         StorageDead(_12);
         FakeRead(ForMatchGuard, _3);
@@ -150,21 +146,21 @@ fn main() -> () {
         _1 = const 3_i32;
         StorageDead(_10);
         StorageDead(_11);
-        goto -> bb21;
+        goto -> bb20;
     }
 
-    bb19: {
-        goto -> bb20;
+    bb18: {
+        goto -> bb19;
     }
 
-    bb20: {
+    bb19: {
         StorageDead(_13);
         StorageDead(_12);
         StorageDead(_11);
-        falseEdge -> [real: bb7, imaginary: bb4];
+        falseEdge -> [real: bb7, imaginary: bb5];
     }
 
-    bb21: {
+    bb20: {
         PlaceMention(_1);
         StorageDead(_2);
         StorageDead(_1);
@@ -172,16 +168,12 @@ fn main() -> () {
         return;
     }
 
-    bb22: {
+    bb21: {
         FakeRead(ForMatchedPlace(None), _1);
         unreachable;
     }
 
-    bb23: {
-        goto -> bb22;
-    }
-
-    bb24 (cleanup): {
+    bb22 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir
index faa2456fd10..b0ebdc37b06 100644
--- a/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir
+++ b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir
@@ -6,17 +6,16 @@ fn match_bool(_1: bool) -> usize {
 
     bb0: {
         PlaceMention(_1);
-        switchInt(_1) -> [0: bb2, otherwise: bb4];
+        switchInt(_1) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
-        FakeRead(ForMatchedPlace(None), _1);
-        unreachable;
+        _0 = const 20_usize;
+        goto -> bb6;
     }
 
     bb2: {
-        _0 = const 20_usize;
-        goto -> bb7;
+        falseEdge -> [real: bb5, imaginary: bb1];
     }
 
     bb3: {
@@ -24,19 +23,16 @@ fn match_bool(_1: bool) -> usize {
     }
 
     bb4: {
-        falseEdge -> [real: bb6, imaginary: bb2];
+        FakeRead(ForMatchedPlace(None), _1);
+        unreachable;
     }
 
     bb5: {
-        goto -> bb2;
-    }
-
-    bb6: {
         _0 = const 10_usize;
-        goto -> bb7;
+        goto -> bb6;
     }
 
-    bb7: {
+    bb6: {
         return;
     }
 }
diff --git a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir
index 905aa19da70..5e685f43cd6 100644
--- a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir
+++ b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir
@@ -8,7 +8,7 @@ fn match_enum(_1: E1) -> bool {
     bb0: {
         PlaceMention(_1);
         _2 = discriminant(_1);
-        switchInt(move _2) -> [0: bb3, 1: bb5, 2: bb7, otherwise: bb2];
+        switchInt(move _2) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb1];
     }
 
     bb1: {
@@ -17,44 +17,40 @@ fn match_enum(_1: E1) -> bool {
     }
 
     bb2: {
-        goto -> bb1;
+        goto -> bb8;
     }
 
     bb3: {
-        goto -> bb9;
+        goto -> bb1;
     }
 
     bb4: {
-        goto -> bb2;
+        goto -> bb8;
     }
 
     bb5: {
-        goto -> bb9;
+        goto -> bb1;
     }
 
     bb6: {
-        goto -> bb2;
+        _0 = const false;
+        goto -> bb10;
     }
 
     bb7: {
-        _0 = const false;
-        goto -> bb11;
+        goto -> bb1;
     }
 
     bb8: {
-        goto -> bb2;
+        falseEdge -> [real: bb9, imaginary: bb6];
     }
 
     bb9: {
-        falseEdge -> [real: bb10, imaginary: bb7];
-    }
-
-    bb10: {
         _0 = const true;
-        goto -> bb11;
+        goto -> bb10;
     }
 
-    bb11: {
+    bb10: {
         return;
     }
 }
diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
index 060cd6132e3..2b5dbacc2d9 100644
--- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir
@@ -23,52 +23,52 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
         StorageDead(_5);
         StorageDead(_4);
         PlaceMention(_3);
-        _9 = <str as PartialEq>::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19];
+        _9 = <str as PartialEq>::eq((_3.0: &str), const "a") -> [return: bb9, unwind: bb19];
     }
 
     bb1: {
-        switchInt((_3.1: bool)) -> [0: bb2, otherwise: bb3];
+        switchInt((_3.1: bool)) -> [0: bb10, otherwise: bb11];
     }
 
     bb2: {
-        _0 = const 5_u32;
-        goto -> bb18;
+        falseEdge -> [real: bb12, imaginary: bb5];
     }
 
     bb3: {
-        falseEdge -> [real: bb17, imaginary: bb2];
+        switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb4];
     }
 
     bb4: {
-        falseEdge -> [real: bb12, imaginary: bb7];
+        falseEdge -> [real: bb16, imaginary: bb1];
     }
 
     bb5: {
-        switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb6];
+        _8 = <str as PartialEq>::eq((_3.0: &str), const "b") -> [return: bb8, unwind: bb19];
     }
 
     bb6: {
-        falseEdge -> [real: bb16, imaginary: bb1];
+        switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb7];
     }
 
     bb7: {
-        _8 = <str as PartialEq>::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19];
+        falseEdge -> [real: bb15, imaginary: bb3];
     }
 
     bb8: {
-        switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb9];
+        switchInt(move _8) -> [0: bb1, otherwise: bb6];
     }
 
     bb9: {
-        falseEdge -> [real: bb15, imaginary: bb5];
+        switchInt(move _9) -> [0: bb5, otherwise: bb2];
     }
 
     bb10: {
-        switchInt(move _8) -> [0: bb1, otherwise: bb8];
+        _0 = const 5_u32;
+        goto -> bb18;
     }
 
     bb11: {
-        switchInt(move _9) -> [0: bb7, otherwise: bb4];
+        falseEdge -> [real: bb17, imaginary: bb10];
     }
 
     bb12: {
@@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {
 
     bb14: {
         StorageDead(_10);
-        falseEdge -> [real: bb5, imaginary: bb7];
+        falseEdge -> [real: bb3, imaginary: bb5];
     }
 
     bb15: {
diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
index db758368a13..6d3b2cf2910 100644
--- a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
+++ b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
@@ -26,7 +26,7 @@ fn move_out_by_subslice() -> () {
         StorageLive(_2);
         _3 = SizeOf(i32);
         _4 = AlignOf(i32);
-        _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14];
+        _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13];
     }
 
     bb1: {
@@ -34,7 +34,7 @@ fn move_out_by_subslice() -> () {
         _6 = ShallowInitBox(move _5, i32);
         (*_6) = const 1_i32;
         _2 = move _6;
-        drop(_6) -> [return: bb2, unwind: bb13];
+        drop(_6) -> [return: bb2, unwind: bb12];
     }
 
     bb2: {
@@ -42,7 +42,7 @@ fn move_out_by_subslice() -> () {
         StorageLive(_7);
         _8 = SizeOf(i32);
         _9 = AlignOf(i32);
-        _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13];
+        _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12];
     }
 
     bb3: {
@@ -50,18 +50,18 @@ fn move_out_by_subslice() -> () {
         _11 = ShallowInitBox(move _10, i32);
         (*_11) = const 2_i32;
         _7 = move _11;
-        drop(_11) -> [return: bb4, unwind: bb12];
+        drop(_11) -> [return: bb4, unwind: bb11];
     }
 
     bb4: {
         StorageDead(_11);
         _1 = [move _2, move _7];
-        drop(_7) -> [return: bb5, unwind: bb13];
+        drop(_7) -> [return: bb5, unwind: bb12];
     }
 
     bb5: {
         StorageDead(_7);
-        drop(_2) -> [return: bb6, unwind: bb14];
+        drop(_2) -> [return: bb6, unwind: bb13];
     }
 
     bb6: {
@@ -71,7 +71,7 @@ fn move_out_by_subslice() -> () {
         StorageLive(_12);
         _12 = move _1[0..2];
         _0 = const ();
-        drop(_12) -> [return: bb9, unwind: bb11];
+        drop(_12) -> [return: bb8, unwind: bb10];
     }
 
     bb7: {
@@ -80,32 +80,28 @@ fn move_out_by_subslice() -> () {
     }
 
     bb8: {
-        goto -> bb7;
-    }
-
-    bb9: {
         StorageDead(_12);
-        drop(_1) -> [return: bb10, unwind: bb14];
+        drop(_1) -> [return: bb9, unwind: bb13];
     }
 
-    bb10: {
+    bb9: {
         StorageDead(_1);
         return;
     }
 
+    bb10 (cleanup): {
+        drop(_1) -> [return: bb13, unwind terminate(cleanup)];
+    }
+
     bb11 (cleanup): {
-        drop(_1) -> [return: bb14, unwind terminate(cleanup)];
+        drop(_7) -> [return: bb12, unwind terminate(cleanup)];
     }
 
     bb12 (cleanup): {
-        drop(_7) -> [return: bb13, unwind terminate(cleanup)];
+        drop(_2) -> [return: bb13, unwind terminate(cleanup)];
     }
 
     bb13 (cleanup): {
-        drop(_2) -> [return: bb14, unwind terminate(cleanup)];
-    }
-
-    bb14 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
index 84cd557715c..003b90a912d 100644
--- a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
+++ b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
@@ -26,7 +26,7 @@ fn move_out_from_end() -> () {
         StorageLive(_2);
         _3 = SizeOf(i32);
         _4 = AlignOf(i32);
-        _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14];
+        _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13];
     }
 
     bb1: {
@@ -34,7 +34,7 @@ fn move_out_from_end() -> () {
         _6 = ShallowInitBox(move _5, i32);
         (*_6) = const 1_i32;
         _2 = move _6;
-        drop(_6) -> [return: bb2, unwind: bb13];
+        drop(_6) -> [return: bb2, unwind: bb12];
     }
 
     bb2: {
@@ -42,7 +42,7 @@ fn move_out_from_end() -> () {
         StorageLive(_7);
         _8 = SizeOf(i32);
         _9 = AlignOf(i32);
-        _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13];
+        _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12];
     }
 
     bb3: {
@@ -50,18 +50,18 @@ fn move_out_from_end() -> () {
         _11 = ShallowInitBox(move _10, i32);
         (*_11) = const 2_i32;
         _7 = move _11;
-        drop(_11) -> [return: bb4, unwind: bb12];
+        drop(_11) -> [return: bb4, unwind: bb11];
     }
 
     bb4: {
         StorageDead(_11);
         _1 = [move _2, move _7];
-        drop(_7) -> [return: bb5, unwind: bb13];
+        drop(_7) -> [return: bb5, unwind: bb12];
     }
 
     bb5: {
         StorageDead(_7);
-        drop(_2) -> [return: bb6, unwind: bb14];
+        drop(_2) -> [return: bb6, unwind: bb13];
     }
 
     bb6: {
@@ -71,7 +71,7 @@ fn move_out_from_end() -> () {
         StorageLive(_12);
         _12 = move _1[1 of 2];
         _0 = const ();
-        drop(_12) -> [return: bb9, unwind: bb11];
+        drop(_12) -> [return: bb8, unwind: bb10];
     }
 
     bb7: {
@@ -80,32 +80,28 @@ fn move_out_from_end() -> () {
     }
 
     bb8: {
-        goto -> bb7;
-    }
-
-    bb9: {
         StorageDead(_12);
-        drop(_1) -> [return: bb10, unwind: bb14];
+        drop(_1) -> [return: bb9, unwind: bb13];
     }
 
-    bb10: {
+    bb9: {
         StorageDead(_1);
         return;
     }
 
+    bb10 (cleanup): {
+        drop(_1) -> [return: bb13, unwind terminate(cleanup)];
+    }
+
     bb11 (cleanup): {
-        drop(_1) -> [return: bb14, unwind terminate(cleanup)];
+        drop(_7) -> [return: bb12, unwind terminate(cleanup)];
     }
 
     bb12 (cleanup): {
-        drop(_7) -> [return: bb13, unwind terminate(cleanup)];
+        drop(_2) -> [return: bb13, unwind terminate(cleanup)];
     }
 
     bb13 (cleanup): {
-        drop(_2) -> [return: bb14, unwind terminate(cleanup)];
-    }
-
-    bb14 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff b/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff
index ac33f51984c..8088984bc77 100644
--- a/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff
+++ b/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff
@@ -119,11 +119,7 @@
       }
   }
   
-  ALLOC0 (size: 8, align: 4) {
-      20 00 00 00 20 00 00 00                         │  ... ...
-  }
+  ALLOC0 (size: 8, align: 4) { .. }
   
-  ALLOC1 (size: 4, align: 2) {
-      01 00 63 00                                     │ ..c.
-  }
+  ALLOC1 (size: 4, align: 2) { .. }
   
diff --git a/tests/mir-opt/const_debuginfo.rs b/tests/mir-opt/const_debuginfo.rs
index 907d7fef067..3b2bc4559ce 100644
--- a/tests/mir-opt/const_debuginfo.rs
+++ b/tests/mir-opt/const_debuginfo.rs
@@ -1,5 +1,5 @@
 //@ test-mir-pass: SingleUseConsts
-//@ compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN
+//@ compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN -Zdump-mir-exclude-alloc-bytes
 
 #![allow(unused)]
 
diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
index 3f4958f60e8..ac372f83726 100644
--- a/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
+++ b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
@@ -44,9 +44,7 @@
           StorageDead(_2);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/address_of_pair.rs b/tests/mir-opt/const_prop/address_of_pair.rs
index 6d0c0f8ad52..9acaaa0ccaf 100644
--- a/tests/mir-opt/const_prop/address_of_pair.rs
+++ b/tests/mir-opt/const_prop/address_of_pair.rs
@@ -1,4 +1,5 @@
 //@ test-mir-pass: GVN
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 
 // EMIT_MIR address_of_pair.fn0.GVN.diff
 pub fn fn0() -> bool {
diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
index 0e93c167ebc..798f957caa5 100644
--- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
@@ -24,9 +24,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     02 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
index 589eed5776c..a09f8ee5be1 100644
--- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
@@ -24,9 +24,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     02 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/checked_add.rs b/tests/mir-opt/const_prop/checked_add.rs
index 0560b049573..d450f7d03f3 100644
--- a/tests/mir-opt/const_prop/checked_add.rs
+++ b/tests/mir-opt/const_prop/checked_add.rs
@@ -1,6 +1,6 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //@ test-mir-pass: GVN
-//@ compile-flags: -C overflow-checks=on
+//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes
 
 // EMIT_MIR checked_add.main.GVN.diff
 fn main() {
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff
index b6ff7b0fc23..7584353620e 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff
@@ -24,9 +24,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     2a 00 00 00 2b 00 00 00                         │ *...+...
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate.rs
index 7de647ed9c3..80cd75215c1 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.rs
@@ -1,4 +1,5 @@
 //@ test-mir-pass: GVN
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 
 // EMIT_MIR mutable_variable_aggregate.main.GVN.diff
 fn main() {
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff
index 4ed7c985147..e16e2969eb8 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff
@@ -31,9 +31,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     2a 00 00 00 2b 00 00 00                         │ *...+...
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
index 5656c0e7a68..856afd53ab4 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
@@ -1,4 +1,5 @@
 //@ test-mir-pass: GVN
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 
 // EMIT_MIR mutable_variable_aggregate_mut_ref.main.GVN.diff
 fn main() {
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff
index d1d23675bfd..19d79694666 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff
@@ -48,9 +48,7 @@
 +         nop;
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff
index 4d69c9ce2ef..2bb277bf27f 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff
@@ -48,9 +48,7 @@
 +         nop;
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
index cc92949128f..2c6cc0db6b2 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
@@ -1,5 +1,6 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //@ test-mir-pass: GVN
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 
 // EMIT_MIR mutable_variable_unprop_assign.main.GVN.diff
 fn main() {
diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
index b2d40daa80c..037fe60c2fd 100644
--- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
@@ -17,9 +17,7 @@
 +         _0 = const 4_u32;
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     04 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
index 2eafc51cd3d..438a1cebea8 100644
--- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
@@ -17,9 +17,7 @@
 +         _0 = const 4_u32;
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     04 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir
index f87c26bb004..66fd61cc3ae 100644
--- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir
+++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir
@@ -15,6 +15,4 @@ fn add() -> u32 {
     }
 }
 
-ALLOC0 (size: 8, align: 4) {
-    04 00 00 00 00 __ __ __                         │ .....░░░
-}
+ALLOC0 (size: 8, align: 4) { .. }
diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir
index 33f97591387..f9b07a59de9 100644
--- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir
+++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir
@@ -15,6 +15,4 @@ fn add() -> u32 {
     }
 }
 
-ALLOC0 (size: 8, align: 4) {
-    04 00 00 00 00 __ __ __                         │ .....░░░
-}
+ALLOC0 (size: 8, align: 4) { .. }
diff --git a/tests/mir-opt/const_prop/return_place.rs b/tests/mir-opt/const_prop/return_place.rs
index e7eea11ae49..c5293aa73e5 100644
--- a/tests/mir-opt/const_prop/return_place.rs
+++ b/tests/mir-opt/const_prop/return_place.rs
@@ -1,6 +1,6 @@
 //@ test-mir-pass: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-//@ compile-flags: -C overflow-checks=on
+//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes
 
 // EMIT_MIR return_place.add.GVN.diff
 // EMIT_MIR return_place.add.PreCodegen.before.mir
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
index ef298dddd5a..8415789de6e 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
@@ -49,9 +49,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 12, align: 4) {
-+     01 00 00 00 02 00 00 00 03 00 00 00             │ ............
   }
++ 
++ ALLOC0 (size: 12, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
index 5379df3f60b..fea7caac3cd 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
@@ -49,9 +49,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 12, align: 4) {
-+     01 00 00 00 02 00 00 00 03 00 00 00             │ ............
   }
++ 
++ ALLOC0 (size: 12, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
index ef298dddd5a..8415789de6e 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
@@ -49,9 +49,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 12, align: 4) {
-+     01 00 00 00 02 00 00 00 03 00 00 00             │ ............
   }
++ 
++ ALLOC0 (size: 12, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
index 5379df3f60b..fea7caac3cd 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
@@ -49,9 +49,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 12, align: 4) {
-+     01 00 00 00 02 00 00 00 03 00 00 00             │ ............
   }
++ 
++ ALLOC0 (size: 12, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs
index 63cdbf01b3e..265a496f39a 100644
--- a/tests/mir-opt/const_prop/slice_len.rs
+++ b/tests/mir-opt/const_prop/slice_len.rs
@@ -1,5 +1,5 @@
 //@ test-mir-pass: GVN
-//@ compile-flags: -Zmir-enable-passes=+InstSimplify
+//@ compile-flags: -Zmir-enable-passes=+InstSimplify -Zdump-mir-exclude-alloc-bytes
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff
index c2f3fb1b3b5..bf8fece3d37 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff
@@ -31,9 +31,7 @@
 +         nop;
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff
index 55d9a3b0cac..02a75849d88 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff
@@ -31,9 +31,7 @@
 +         nop;
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.rs b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
index e42a62cb6fd..baed5670dda 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
@@ -1,4 +1,5 @@
 //@ test-mir-pass: GVN
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // EMIT_MIR tuple_literal_propagation.main.GVN.diff
 
diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff
new file mode 100644
index 00000000000..1aeaaff21dc
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff
@@ -0,0 +1,65 @@
+- // MIR for `foo` before DataflowConstProp
++ // MIR for `foo` after DataflowConstProp
+  
+  fn foo() -> u32 {
+      let mut _0: u32;
+      let _1: (u32, u32);
+      let mut _4: bool;
+      let mut _5: u32;
+      scope 1 {
+          debug a => _1;
+          let _2: (u32, u32);
+          scope 2 {
+              debug b => _2;
+              let _3: u32;
+              scope 3 {
+                  debug c => _3;
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const Foo;
+          StorageLive(_2);
+-         _2 = _1;
++         _2 = const (5_u32, 3_u32);
+          StorageLive(_3);
+-         _3 = (_2.1: u32);
++         _3 = const 3_u32;
+          StorageLive(_4);
+          StorageLive(_5);
+-         _5 = _3;
+-         _4 = Ge(move _5, const 2_u32);
+-         switchInt(move _4) -> [0: bb2, otherwise: bb1];
++         _5 = const 3_u32;
++         _4 = const true;
++         switchInt(const true) -> [0: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageDead(_5);
+-         _0 = (_2.0: u32);
++         _0 = const 5_u32;
+          goto -> bb3;
+      }
+  
+      bb2: {
+          StorageDead(_5);
+          _0 = const 13_u32;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_4);
+          StorageDead(_3);
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     05 00 00 00 03 00 00 00                         │ ........
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs
new file mode 100644
index 00000000000..aca5f047222
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs
@@ -0,0 +1,42 @@
+//! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning
+//! the contained scalars.
+//@ test-mir-pass: DataflowConstProp
+
+const Foo: (u32, u32) = (5, 3);
+
+fn foo() -> u32 {
+    // CHECK-LABEL: fn foo(
+    // CHECK: debug a => [[a:_.*]];
+    // CHECK: debug b => [[b:_.*]];
+    // CHECK: debug c => [[c:_.*]];
+
+    // CHECK:bb0: {
+    // CHECK:    [[a]] = const Foo;
+    // CHECK:    [[b]] = const (5_u32, 3_u32);
+    // CHECK:    [[c]] = const 3_u32;
+    // CHECK:    {{_.*}} = const 3_u32;
+    // CHECK:    {{_.*}} = const true;
+    // CHECK:    switchInt(const true) -> [0: bb2, otherwise: bb1];
+
+    // CHECK:bb1: {
+    // CHECK:    _0 = const 5_u32;
+    // CHECK:    goto -> bb3;
+
+    // CHECK:bb2: {
+    // CHECK:    _0 = const 13_u32;
+    // CHECK:    goto -> bb3;
+
+    let a = Foo;
+    // This copies the struct in `a`. We want to ensure that we do track the contents of `a`
+    // because we need to read `b` later.
+    let b = a;
+    let c = b.1;
+    if c >= 2 { b.0 } else { 13 }
+}
+
+fn main() {
+    // CHECK-LABEL: fn main(
+    foo();
+}
+
+// EMIT_MIR aggregate_copy.foo.DataflowConstProp.diff
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
index 53663c6476b..79ea5561748 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
@@ -76,13 +76,9 @@
           StorageDead(_1);
           return;
       }
-+ }
+  }
 + 
-+ ALLOC0 (size: 8, align: 4) {
-+     00 00 00 80 01 __ __ __                         │ .....░░░
-+ }
++ ALLOC0 (size: 8, align: 4) { .. }
 + 
-+ ALLOC1 (size: 8, align: 4) {
-+     03 00 00 00 00 __ __ __                         │ .....░░░
-  }
++ ALLOC1 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
index 34feb2a6406..bd22c50dd8f 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
@@ -76,13 +76,9 @@
           StorageDead(_1);
           return;
       }
-+ }
+  }
 + 
-+ ALLOC0 (size: 8, align: 4) {
-+     00 00 00 80 01 __ __ __                         │ .....░░░
-+ }
++ ALLOC0 (size: 8, align: 4) { .. }
 + 
-+ ALLOC1 (size: 8, align: 4) {
-+     03 00 00 00 00 __ __ __                         │ .....░░░
-  }
++ ALLOC1 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs
index a73693464f9..f5a6cdb2c8d 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.rs
+++ b/tests/mir-opt/dataflow-const-prop/checked.rs
@@ -1,5 +1,5 @@
 //@ test-mir-pass: DataflowConstProp
-//@ compile-flags: -Coverflow-checks=on
+//@ compile-flags: -Coverflow-checks=on -Zdump-mir-exclude-alloc-bytes
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 // EMIT_MIR checked.main.DataflowConstProp.diff
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
index 8005bc23cf6..4097e060f4d 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
@@ -94,15 +94,9 @@
       }
   }
   
-  ALLOC2 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
+  ALLOC2 (size: 8, align: 4) { .. }
   
-  ALLOC1 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
+  ALLOC1 (size: 8, align: 4) { .. }
   
-  ALLOC0 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
+  ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
index 42b1be32387..ff44d0df5e3 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -98,15 +98,9 @@
       }
   }
   
-  ALLOC2 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
+  ALLOC2 (size: 8, align: 4) { .. }
   
-  ALLOC1 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
+  ALLOC1 (size: 8, align: 4) { .. }
   
-  ALLOC0 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
+  ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
index 7b57b0db50c..3662c3b59d2 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
@@ -94,15 +94,9 @@
       }
   }
   
-  ALLOC2 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
+  ALLOC2 (size: 16, align: 8) { .. }
   
-  ALLOC1 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
+  ALLOC1 (size: 16, align: 8) { .. }
   
-  ALLOC0 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
+  ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
index 2e75a63e290..68dee57dee9 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -98,15 +98,9 @@
       }
   }
   
-  ALLOC2 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
+  ALLOC2 (size: 16, align: 8) { .. }
   
-  ALLOC1 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
+  ALLOC1 (size: 16, align: 8) { .. }
   
-  ALLOC0 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
+  ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
index 06011f9d759..9d96e895c8a 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
@@ -102,17 +102,11 @@
           _0 = const ();
           drop(_1) -> [return: bb1, unwind unreachable];
       }
-+ }
+  }
 + 
-+ ALLOC2 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-+ }
++ ALLOC2 (size: 8, align: 4) { .. }
 + 
-+ ALLOC1 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-+ }
++ ALLOC1 (size: 8, align: 4) { .. }
 + 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-  }
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
index eb4a3ffd91d..0bdff584b01 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
@@ -106,17 +106,11 @@
           _0 = const ();
           drop(_1) -> [return: bb1, unwind: bb2];
       }
-+ }
+  }
 + 
-+ ALLOC2 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-+ }
++ ALLOC2 (size: 8, align: 4) { .. }
 + 
-+ ALLOC1 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-+ }
++ ALLOC1 (size: 8, align: 4) { .. }
 + 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-  }
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
index a7cc243e548..99e96fe5d70 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
@@ -102,17 +102,11 @@
           _0 = const ();
           drop(_1) -> [return: bb1, unwind unreachable];
       }
-+ }
+  }
 + 
-+ ALLOC2 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-+ }
++ ALLOC2 (size: 16, align: 8) { .. }
 + 
-+ ALLOC1 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-+ }
++ ALLOC1 (size: 16, align: 8) { .. }
 + 
-+ ALLOC0 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
++ ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
index c905a48862c..5eefabeac38 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
@@ -106,17 +106,11 @@
           _0 = const ();
           drop(_1) -> [return: bb1, unwind: bb2];
       }
-+ }
+  }
 + 
-+ ALLOC2 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-+ }
++ ALLOC2 (size: 16, align: 8) { .. }
 + 
-+ ALLOC1 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-+ }
++ ALLOC1 (size: 16, align: 8) { .. }
 + 
-+ ALLOC0 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
++ ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
index 3a0cbac328c..087bd7a1857 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
@@ -1,5 +1,5 @@
 //@ test-mir-pass: DataflowConstProp
-//@ compile-flags: -Zmir-enable-passes=+GVN,+Inline
+//@ compile-flags: -Zmir-enable-passes=+GVN,+Inline -Zdump-mir-exclude-alloc-bytes
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs
index 946cfa4c76c..37304e3a270 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.rs
+++ b/tests/mir-opt/dataflow-const-prop/enum.rs
@@ -1,4 +1,5 @@
 //@ test-mir-pass: DataflowConstProp
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 #![feature(custom_mir, core_intrinsics, rustc_attrs)]
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
index 89ed26f065b..a64dda0d06c 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff
@@ -60,9 +60,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     00 00 00 00 00 00 00 00                         │ ........
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
index 89ed26f065b..a64dda0d06c 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff
@@ -60,9 +60,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     00 00 00 00 00 00 00 00                         │ ........
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
index fe8ed011489..b4d14f25fe2 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff
@@ -43,7 +43,7 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = const {ALLOC1: &E};
+          _2 = const {ALLOC0: &E};
 -         _1 = (*_2);
 +         _1 = const E::V1(0_i32);
           StorageDead(_2);
@@ -79,7 +79,7 @@
       bb4: {
           StorageLive(_7);
           StorageLive(_8);
-          _8 = const {ALLOC2: &&E};
+          _8 = const {ALLOC1: &&E};
           _7 = (*_8);
           StorageDead(_8);
           StorageLive(_9);
@@ -111,21 +111,14 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC3 (size: 8, align: 4) {
-+     00 00 00 00 00 00 00 00                         │ ........
   }
   
-  ALLOC2 (static: RC, size: 4, align: 4) {
-      ╾ALLOC0<imm>╼                                     │ ╾──╼
-  }
++ ALLOC2 (size: 8, align: 4) { .. }
++ 
+  ALLOC1 (static: RC, size: 4, align: 4) { .. }
   
-  ALLOC0 (size: 8, align: 4) {
-      01 00 00 00 04 00 00 00                         │ ........
-  }
+- ALLOC2 (size: 8, align: 4) { .. }
++ ALLOC3 (size: 8, align: 4) { .. }
   
-  ALLOC1 (static: statics::C, size: 8, align: 4) {
-      00 00 00 00 00 00 00 00                         │ ........
-  }
+  ALLOC0 (static: statics::C, size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
index df3a989d09e..57d02b87d13 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff
@@ -43,7 +43,7 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = const {ALLOC1: &E};
+          _2 = const {ALLOC0: &E};
 -         _1 = (*_2);
 +         _1 = const E::V1(0_i32);
           StorageDead(_2);
@@ -79,7 +79,7 @@
       bb4: {
           StorageLive(_7);
           StorageLive(_8);
-          _8 = const {ALLOC2: &&E};
+          _8 = const {ALLOC1: &&E};
           _7 = (*_8);
           StorageDead(_8);
           StorageLive(_9);
@@ -111,21 +111,14 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC3 (size: 8, align: 4) {
-+     00 00 00 00 00 00 00 00                         │ ........
   }
   
-  ALLOC2 (static: RC, size: 8, align: 8) {
-      ╾ALLOC0<imm>╼                         │ ╾──────╼
-  }
++ ALLOC2 (size: 8, align: 4) { .. }
++ 
+  ALLOC1 (static: RC, size: 8, align: 8) { .. }
   
-  ALLOC0 (size: 8, align: 4) {
-      01 00 00 00 04 00 00 00                         │ ........
-  }
+- ALLOC2 (size: 8, align: 4) { .. }
++ ALLOC3 (size: 8, align: 4) { .. }
   
-  ALLOC1 (static: statics::C, size: 8, align: 4) {
-      00 00 00 00 00 00 00 00                         │ ........
-  }
+  ALLOC0 (static: statics::C, size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
index f674169e28b..5e89382ea8f 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff
@@ -106,13 +106,12 @@
 -         _7 = (_10.0: f32);
 +         _7 = const 4f32;
           StorageLive(_8);
--         _8 = (_10.1: std::option::Option<S>);
-+         _8 = const Option::<S>::Some(S(1_i32));
+          _8 = (_10.1: std::option::Option<S>);
           StorageLive(_9);
           _9 = (_10.2: &[f32]);
           StorageDead(_10);
           StorageLive(_14);
-          _14 = const {ALLOC4: &&SmallStruct};
+          _14 = const {ALLOC0: &&SmallStruct};
           _31 = deref_copy (*_14);
           StorageLive(_11);
           _32 = deref_copy (*_14);
@@ -149,7 +148,7 @@
           _21 = (_22.2: &[f32]);
           StorageDead(_22);
           StorageLive(_26);
-          _26 = const {ALLOC5: &&BigStruct};
+          _26 = const {ALLOC1: &&BigStruct};
           _35 = deref_copy (*_26);
           StorageLive(_23);
           _36 = deref_copy (*_26);
@@ -157,8 +156,7 @@
 +         _23 = const 82f32;
           StorageLive(_24);
           _37 = deref_copy (*_26);
--         _24 = ((*_37).1: std::option::Option<S>);
-+         _24 = const Option::<S>::Some(S(35_i32));
+          _24 = ((*_37).1: std::option::Option<S>);
           StorageLive(_25);
           _38 = deref_copy (*_26);
           _25 = ((*_38).2: &[f32]);
@@ -168,12 +166,11 @@
 -         _28 = _23;
 +         _28 = const 82f32;
           StorageLive(_29);
--         _29 = _24;
-+         _29 = const Option::<S>::Some(S(35_i32));
+          _29 = _24;
           StorageLive(_30);
           _30 = _25;
 -         _27 = BigStruct(move _28, move _29, move _30);
-+         _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
++         _27 = BigStruct(const 82f32, move _29, move _30);
           StorageDead(_30);
           StorageDead(_29);
           StorageDead(_28);
@@ -197,51 +194,23 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC6 (size: 8, align: 4) {
-+     01 00 00 00 23 00 00 00                         │ ....#...
-+ }
-+ 
-+ ALLOC7 (size: 8, align: 4) {
-+     01 00 00 00 23 00 00 00                         │ ....#...
-+ }
-+ 
-+ ALLOC8 (size: 8, align: 4) {
-+     01 00 00 00 23 00 00 00                         │ ....#...
-+ }
-+ 
-+ ALLOC9 (size: 8, align: 4) {
-+     01 00 00 00 01 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC10 (size: 4, align: 4) {
-+     01 00 00 00                                     │ ....
   }
   
-  ALLOC5 (static: BIG_STAT, size: 4, align: 4) {
-      ╾ALLOC0<imm>╼                                     │ ╾──╼
-  }
++ ALLOC2 (size: 4, align: 4) { .. }
++ 
+  ALLOC1 (static: BIG_STAT, size: 4, align: 4) { .. }
   
-  ALLOC0 (size: 20, align: 4) {
-      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1<imm>╼ 02 00 00 00 │ ....#...╾──╼....
-      0x10 │ 00 00 a4 42                                     │ ...B
-  }
+- ALLOC2 (size: 20, align: 4) { .. }
++ ALLOC3 (size: 20, align: 4) { .. }
   
-  ALLOC1 (size: 8, align: 4) {
-      00 00 34 42 00 00 90 42                         │ ..4B...B
-  }
+- ALLOC3 (size: 8, align: 4) { .. }
++ ALLOC4 (size: 8, align: 4) { .. }
   
-  ALLOC4 (static: SMALL_STAT, size: 4, align: 4) {
-      ╾ALLOC2<imm>╼                                     │ ╾──╼
-  }
+  ALLOC0 (static: SMALL_STAT, size: 4, align: 4) { .. }
   
-  ALLOC2 (size: 20, align: 4) {
-      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3<imm>╼ 01 00 00 00 │ ....░░░░╾──╼....
-      0x10 │ 00 00 10 41                                     │ ...A
-  }
+- ALLOC4 (size: 20, align: 4) { .. }
++ ALLOC5 (size: 20, align: 4) { .. }
   
-  ALLOC3 (size: 4, align: 4) {
-      00 00 50 41                                     │ ..PA
-  }
+- ALLOC5 (size: 4, align: 4) { .. }
++ ALLOC6 (size: 4, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
index c2608190a6b..a707d7e5e76 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff
@@ -106,13 +106,12 @@
 -         _7 = (_10.0: f32);
 +         _7 = const 4f32;
           StorageLive(_8);
--         _8 = (_10.1: std::option::Option<S>);
-+         _8 = const Option::<S>::Some(S(1_i32));
+          _8 = (_10.1: std::option::Option<S>);
           StorageLive(_9);
           _9 = (_10.2: &[f32]);
           StorageDead(_10);
           StorageLive(_14);
-          _14 = const {ALLOC4: &&SmallStruct};
+          _14 = const {ALLOC0: &&SmallStruct};
           _31 = deref_copy (*_14);
           StorageLive(_11);
           _32 = deref_copy (*_14);
@@ -149,7 +148,7 @@
           _21 = (_22.2: &[f32]);
           StorageDead(_22);
           StorageLive(_26);
-          _26 = const {ALLOC5: &&BigStruct};
+          _26 = const {ALLOC1: &&BigStruct};
           _35 = deref_copy (*_26);
           StorageLive(_23);
           _36 = deref_copy (*_26);
@@ -157,8 +156,7 @@
 +         _23 = const 82f32;
           StorageLive(_24);
           _37 = deref_copy (*_26);
--         _24 = ((*_37).1: std::option::Option<S>);
-+         _24 = const Option::<S>::Some(S(35_i32));
+          _24 = ((*_37).1: std::option::Option<S>);
           StorageLive(_25);
           _38 = deref_copy (*_26);
           _25 = ((*_38).2: &[f32]);
@@ -168,12 +166,11 @@
 -         _28 = _23;
 +         _28 = const 82f32;
           StorageLive(_29);
--         _29 = _24;
-+         _29 = const Option::<S>::Some(S(35_i32));
+          _29 = _24;
           StorageLive(_30);
           _30 = _25;
 -         _27 = BigStruct(move _28, move _29, move _30);
-+         _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30);
++         _27 = BigStruct(const 82f32, move _29, move _30);
           StorageDead(_30);
           StorageDead(_29);
           StorageDead(_28);
@@ -197,51 +194,23 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC6 (size: 8, align: 4) {
-+     01 00 00 00 23 00 00 00                         │ ....#...
-+ }
-+ 
-+ ALLOC7 (size: 8, align: 4) {
-+     01 00 00 00 23 00 00 00                         │ ....#...
-+ }
-+ 
-+ ALLOC8 (size: 8, align: 4) {
-+     01 00 00 00 23 00 00 00                         │ ....#...
-+ }
-+ 
-+ ALLOC9 (size: 8, align: 4) {
-+     01 00 00 00 01 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC10 (size: 4, align: 4) {
-+     01 00 00 00                                     │ ....
   }
   
-  ALLOC5 (static: BIG_STAT, size: 8, align: 8) {
-      ╾ALLOC0<imm>╼                         │ ╾──────╼
-  }
++ ALLOC2 (size: 4, align: 4) { .. }
++ 
+  ALLOC1 (static: BIG_STAT, size: 8, align: 8) { .. }
   
-  ALLOC0 (size: 32, align: 8) {
-      0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1<imm>╼ │ ....#...╾──────╼
-      0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........B░░░░
-  }
+- ALLOC2 (size: 32, align: 8) { .. }
++ ALLOC3 (size: 32, align: 8) { .. }
   
-  ALLOC1 (size: 8, align: 4) {
-      00 00 34 42 00 00 90 42                         │ ..4B...B
-  }
+- ALLOC3 (size: 8, align: 4) { .. }
++ ALLOC4 (size: 8, align: 4) { .. }
   
-  ALLOC4 (static: SMALL_STAT, size: 8, align: 8) {
-      ╾ALLOC2<imm>╼                         │ ╾──────╼
-  }
+  ALLOC0 (static: SMALL_STAT, size: 8, align: 8) { .. }
   
-  ALLOC2 (size: 32, align: 8) {
-      0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3<imm>╼ │ ....░░░░╾──────╼
-      0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........A░░░░
-  }
+- ALLOC4 (size: 32, align: 8) { .. }
++ ALLOC5 (size: 32, align: 8) { .. }
   
-  ALLOC3 (size: 4, align: 4) {
-      00 00 50 41                                     │ ..PA
-  }
+- ALLOC5 (size: 4, align: 4) { .. }
++ ALLOC6 (size: 4, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs
index eed782c9036..89ad1b87029 100644
--- a/tests/mir-opt/dataflow-const-prop/struct.rs
+++ b/tests/mir-opt/dataflow-const-prop/struct.rs
@@ -1,4 +1,5 @@
 //@ test-mir-pass: DataflowConstProp
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 #[derive(Copy, Clone)]
@@ -45,7 +46,7 @@ fn main() {
     const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]);
 
     // CHECK: [[a1]] = const 4f32;
-    // CHECK: [[b1]] = const Option::<S>::Some(S(1_i32));
+    // CHECK: [[b1]] = ({{_.*}}.1: std::option::Option<S>);
     // CHECK: [[c1]] = ({{_.*}}.2: &[f32]);
     let SmallStruct(a1, b1, c1) = SMALL_VAL;
 
@@ -68,12 +69,12 @@ fn main() {
 
     static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]);
     // CHECK: [[a4]] = const 82f32;
-    // CHECK: [[b4]] = const Option::<S>::Some(S(35_i32));
+    // CHECK: [[b4]] = ((*{{_.*}}).1: std::option::Option<S>);
     // CHECK: [[c4]] = ((*{{_.*}}).2: &[f32]);
     let BigStruct(a4, b4, c4) = *BIG_STAT;
 
     // We arbitrarily limit the size of synthetized values to 4 pointers.
     // `BigStruct` can be read, but we will keep a MIR aggregate for this.
-    // CHECK: [[bs]] = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move {{_.*}});
+    // CHECK: [[bs]] = BigStruct(const 82f32, move {{.*}}, move {{_.*}});
     let bs = BigStruct(a4, b4, c4);
 }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
index 44dd4017409..a023243ad9d 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
@@ -7,10 +7,20 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = Less;
-          _0 = move _1 as i8 (Transmute);
+-         _1 = Less;
+-         _0 = move _1 as i8 (Transmute);
++         _1 = const Less;
++         _0 = const std::cmp::Ordering::Less as i8 (Transmute);
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 1, align: 1) {
++     ff                                              │ .
++ }
++ 
++ ALLOC1 (size: 1, align: 1) {
++     ff                                              │ .
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
index 44dd4017409..a023243ad9d 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
@@ -7,10 +7,20 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = Less;
-          _0 = move _1 as i8 (Transmute);
+-         _1 = Less;
+-         _0 = move _1 as i8 (Transmute);
++         _1 = const Less;
++         _0 = const std::cmp::Ordering::Less as i8 (Transmute);
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 1, align: 1) {
++     ff                                              │ .
++ }
++ 
++ ALLOC1 (size: 1, align: 1) {
++     ff                                              │ .
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff
index f5723cac7d9..e4031b65caa 100644
--- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff
@@ -92,21 +92,13 @@
           StorageDead(_1);
           return;
       }
-+ }
+  }
 + 
-+ ALLOC0 (size: 8, align: 4) {
-+     02 00 00 00 03 00 00 00                         │ ........
-+ }
++ ALLOC0 (size: 8, align: 4) { .. }
 + 
-+ ALLOC1 (size: 8, align: 4) {
-+     02 00 00 00 03 00 00 00                         │ ........
-+ }
++ ALLOC1 (size: 8, align: 4) { .. }
 + 
-+ ALLOC2 (size: 8, align: 4) {
-+     02 00 00 00 03 00 00 00                         │ ........
-+ }
++ ALLOC2 (size: 8, align: 4) { .. }
 + 
-+ ALLOC3 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
-  }
++ ALLOC3 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff
index f5723cac7d9..e4031b65caa 100644
--- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff
@@ -92,21 +92,13 @@
           StorageDead(_1);
           return;
       }
-+ }
+  }
 + 
-+ ALLOC0 (size: 8, align: 4) {
-+     02 00 00 00 03 00 00 00                         │ ........
-+ }
++ ALLOC0 (size: 8, align: 4) { .. }
 + 
-+ ALLOC1 (size: 8, align: 4) {
-+     02 00 00 00 03 00 00 00                         │ ........
-+ }
++ ALLOC1 (size: 8, align: 4) { .. }
 + 
-+ ALLOC2 (size: 8, align: 4) {
-+     02 00 00 00 03 00 00 00                         │ ........
-+ }
++ ALLOC2 (size: 8, align: 4) { .. }
 + 
-+ ALLOC3 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
-  }
++ ALLOC3 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs
index d624e21f21a..19b675770ab 100644
--- a/tests/mir-opt/dataflow-const-prop/tuple.rs
+++ b/tests/mir-opt/dataflow-const-prop/tuple.rs
@@ -1,4 +1,5 @@
 //@ test-mir-pass: DataflowConstProp
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR tuple.main.DataflowConstProp.diff
diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff
index 938b9bb14ad..3a5762e4f3d 100644
--- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff
+++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff
@@ -22,59 +22,55 @@
   
       bb1: {
           StorageDead(_3);
-          _7 = Len((*_2));
-          _8 = const 4_usize;
-          _9 = Ge(move _7, move _8);
--         switchInt(move _9) -> [0: bb2, otherwise: bb7];
-+         switchInt(move _9) -> [0: bb2, otherwise: bb6];
+          _4 = Len((*_2));
+          _5 = const 4_usize;
+          _6 = Ge(move _4, move _5);
+          switchInt(move _6) -> [0: bb2, otherwise: bb3];
       }
   
       bb2: {
-          _4 = Len((*_2));
-          _5 = const 3_usize;
-          _6 = Ge(move _4, move _5);
--         switchInt(move _6) -> [0: bb3, otherwise: bb4];
-+         switchInt(move _6) -> [0: bb10, otherwise: bb3];
+          _7 = Len((*_2));
+          _8 = const 3_usize;
+          _9 = Ge(move _7, move _8);
+-         switchInt(move _9) -> [0: bb7, otherwise: bb8];
++         switchInt(move _9) -> [0: bb10, otherwise: bb7];
       }
   
       bb3: {
--         _0 = const false;
--         goto -> bb14;
-+         switchInt((*_2)[0 of 3]) -> [47: bb4, otherwise: bb10];
+          switchInt((*_2)[0 of 4]) -> [47: bb4, otherwise: bb2];
       }
   
       bb4: {
--         switchInt((*_2)[0 of 3]) -> [47: bb5, otherwise: bb3];
-+         switchInt((*_2)[1 of 3]) -> [47: bb5, otherwise: bb10];
+          switchInt((*_2)[1 of 4]) -> [47: bb5, otherwise: bb2];
       }
   
       bb5: {
--         switchInt((*_2)[1 of 3]) -> [47: bb6, otherwise: bb3];
-+         switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10];
+          switchInt((*_2)[2 of 4]) -> [47: bb6, otherwise: bb2];
       }
   
       bb6: {
--         switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb3];
-+         switchInt((*_2)[0 of 4]) -> [47: bb7, otherwise: bb2];
+-         switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2];
++         switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2];
       }
   
       bb7: {
--         switchInt((*_2)[0 of 4]) -> [47: bb8, otherwise: bb2];
-+         switchInt((*_2)[1 of 4]) -> [47: bb8, otherwise: bb2];
+-         _0 = const false;
+-         goto -> bb14;
++         switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10];
       }
   
       bb8: {
--         switchInt((*_2)[1 of 4]) -> [47: bb9, otherwise: bb2];
-+         switchInt((*_2)[2 of 4]) -> [47: bb9, otherwise: bb2];
+-         switchInt((*_2)[0 of 3]) -> [47: bb9, otherwise: bb7];
++         switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10];
       }
   
       bb9: {
--         switchInt((*_2)[2 of 4]) -> [47: bb10, otherwise: bb2];
-+         switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2];
+-         switchInt((*_2)[1 of 3]) -> [47: bb10, otherwise: bb7];
++         switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10];
       }
   
       bb10: {
--         switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2];
+-         switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb7];
 -     }
 - 
 -     bb11: {
diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
index ce89694076b..21b197d2f27 100644
--- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
+++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
@@ -22,59 +22,55 @@
   
       bb1: {
           StorageDead(_3);
-          _7 = Len((*_2));
-          _8 = const 4_usize;
-          _9 = Ge(move _7, move _8);
--         switchInt(move _9) -> [0: bb2, otherwise: bb7];
-+         switchInt(move _9) -> [0: bb2, otherwise: bb6];
+          _4 = Len((*_2));
+          _5 = const 4_usize;
+          _6 = Ge(move _4, move _5);
+          switchInt(move _6) -> [0: bb2, otherwise: bb3];
       }
   
       bb2: {
-          _4 = Len((*_2));
-          _5 = const 3_usize;
-          _6 = Ge(move _4, move _5);
--         switchInt(move _6) -> [0: bb3, otherwise: bb4];
-+         switchInt(move _6) -> [0: bb10, otherwise: bb3];
+          _7 = Len((*_2));
+          _8 = const 3_usize;
+          _9 = Ge(move _7, move _8);
+-         switchInt(move _9) -> [0: bb7, otherwise: bb8];
++         switchInt(move _9) -> [0: bb10, otherwise: bb7];
       }
   
       bb3: {
--         _0 = const false;
--         goto -> bb14;
-+         switchInt((*_2)[0 of 3]) -> [47: bb4, otherwise: bb10];
+          switchInt((*_2)[0 of 4]) -> [47: bb4, otherwise: bb2];
       }
   
       bb4: {
--         switchInt((*_2)[0 of 3]) -> [47: bb5, otherwise: bb3];
-+         switchInt((*_2)[1 of 3]) -> [47: bb5, otherwise: bb10];
+          switchInt((*_2)[1 of 4]) -> [47: bb5, otherwise: bb2];
       }
   
       bb5: {
--         switchInt((*_2)[1 of 3]) -> [47: bb6, otherwise: bb3];
-+         switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10];
+          switchInt((*_2)[2 of 4]) -> [47: bb6, otherwise: bb2];
       }
   
       bb6: {
--         switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb3];
-+         switchInt((*_2)[0 of 4]) -> [47: bb7, otherwise: bb2];
+-         switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2];
++         switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2];
       }
   
       bb7: {
--         switchInt((*_2)[0 of 4]) -> [47: bb8, otherwise: bb2];
-+         switchInt((*_2)[1 of 4]) -> [47: bb8, otherwise: bb2];
+-         _0 = const false;
+-         goto -> bb14;
++         switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10];
       }
   
       bb8: {
--         switchInt((*_2)[1 of 4]) -> [47: bb9, otherwise: bb2];
-+         switchInt((*_2)[2 of 4]) -> [47: bb9, otherwise: bb2];
+-         switchInt((*_2)[0 of 3]) -> [47: bb9, otherwise: bb7];
++         switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10];
       }
   
       bb9: {
--         switchInt((*_2)[2 of 4]) -> [47: bb10, otherwise: bb2];
-+         switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2];
+-         switchInt((*_2)[1 of 3]) -> [47: bb10, otherwise: bb7];
++         switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10];
       }
   
       bb10: {
--         switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2];
+-         switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb7];
 -     }
 - 
 -     bb11: {
diff --git a/tests/mir-opt/dest-prop/branch.rs b/tests/mir-opt/dest-prop/branch.rs
index 481d4130c7b..0ac79ee4ec2 100644
--- a/tests/mir-opt/dest-prop/branch.rs
+++ b/tests/mir-opt/dest-prop/branch.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //! Tests that assignment in both branches of an `if` are eliminated.
 //@ test-mir-pass: DestinationPropagation
@@ -12,6 +11,10 @@ fn cond() -> bool {
 
 // EMIT_MIR branch.foo.DestinationPropagation.diff
 fn foo() -> i32 {
+    // CHECK-LABEL: fn foo(
+    // CHECK: debug y => [[y:_.*]];
+    // CHECK: [[y]] = val()
+    // CHECK-NOT: [[y]] = {{_.*}};
     let x = val();
 
     let y = if cond() {
diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.rs b/tests/mir-opt/dest-prop/copy_propagation_arg.rs
index db4969924ff..084bd0544c1 100644
--- a/tests/mir-opt/dest-prop/copy_propagation_arg.rs
+++ b/tests/mir-opt/dest-prop/copy_propagation_arg.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // Check that DestinationPropagation does not propagate an assignment to a function argument
 // (doing so can break usages of the original argument value)
@@ -9,18 +8,29 @@ fn dummy(x: u8) -> u8 {
 
 // EMIT_MIR copy_propagation_arg.foo.DestinationPropagation.diff
 fn foo(mut x: u8) {
+    // CHECK-LABEL: fn foo(
+    // CHECK: debug x => [[x:_.*]];
+    // CHECK: dummy(move [[x]])
+    // CHECK: [[x]] = move {{_.*}};
     // calling `dummy` to make a use of `x` that copyprop cannot eliminate
     x = dummy(x); // this will assign a local to `x`
 }
 
 // EMIT_MIR copy_propagation_arg.bar.DestinationPropagation.diff
 fn bar(mut x: u8) {
+    // CHECK-LABEL: fn bar(
+    // CHECK: debug x => [[x:_.*]];
+    // CHECK: dummy(move [[x]])
+    // CHECK: [[x]] = const 5_u8;
     dummy(x);
     x = 5;
 }
 
 // EMIT_MIR copy_propagation_arg.baz.DestinationPropagation.diff
 fn baz(mut x: i32) -> i32 {
+    // CHECK-LABEL: fn baz(
+    // CHECK: debug x => [[x:_.*]];
+    // CHECK-NOT: [[x]] =
     // self-assignment to a function argument should be eliminated
     x = x;
     x
@@ -28,6 +38,12 @@ fn baz(mut x: i32) -> i32 {
 
 // EMIT_MIR copy_propagation_arg.arg_src.DestinationPropagation.diff
 fn arg_src(mut x: i32) -> i32 {
+    // CHECK-LABEL: fn arg_src(
+    // CHECK: debug x => [[x:_.*]];
+    // CHECK: debug y => [[y:_.*]];
+    // CHECK: [[y]] = [[x]]
+    // CHECK: [[x]] = const 123_i32;
+    // CHECK-NOT: {{_.*}} = [[y]];
     let y = x;
     x = 123; // Don't propagate this assignment to `y`
     y
diff --git a/tests/mir-opt/dest-prop/cycle.rs b/tests/mir-opt/dest-prop/cycle.rs
index e414daf20f2..86b9b713fd0 100644
--- a/tests/mir-opt/dest-prop/cycle.rs
+++ b/tests/mir-opt/dest-prop/cycle.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code.
 //@ test-mir-pass: DestinationPropagation
@@ -8,6 +7,10 @@ fn val() -> i32 {
 
 // EMIT_MIR cycle.main.DestinationPropagation.diff
 fn main() {
+    // CHECK-LABEL: main(
+    // CHECK: debug x => [[x:_.*]];
+    // CHECK: [[x]] = val()
+    // CHECK-NOT: [[x]] = {{_.*}};
     let mut x = val();
     let y = x;
     let z = y;
diff --git a/tests/mir-opt/dest-prop/dead_stores_79191.rs b/tests/mir-opt/dest-prop/dead_stores_79191.rs
index 5c218a328f5..61060e4f850 100644
--- a/tests/mir-opt/dest-prop/dead_stores_79191.rs
+++ b/tests/mir-opt/dest-prop/dead_stores_79191.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //@ test-mir-pass: DestinationPropagation
 
@@ -8,6 +7,13 @@ fn id<T>(x: T) -> T {
 
 // EMIT_MIR dead_stores_79191.f.DestinationPropagation.after.mir
 fn f(mut a: usize) -> usize {
+    // CHECK-LABEL: fn f(
+    // CHECK: debug a => [[a:_.*]];
+    // CHECK: debug b => [[b:_.*]];
+    // CHECK: [[b]] = [[a]];
+    // CHECK: [[a]] = const 5_usize;
+    // CHECK: [[a]] = move [[b]];
+    // CHECK: id::<usize>(move [[a]])
     let b = a;
     a = 5;
     a = b;
diff --git a/tests/mir-opt/dest-prop/dead_stores_better.rs b/tests/mir-opt/dest-prop/dead_stores_better.rs
index 06445dc8703..d2b9fe05712 100644
--- a/tests/mir-opt/dest-prop/dead_stores_better.rs
+++ b/tests/mir-opt/dest-prop/dead_stores_better.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates
 // that that pass enables this one to do more optimizations.
@@ -12,6 +11,13 @@ fn id<T>(x: T) -> T {
 
 // EMIT_MIR dead_stores_better.f.DestinationPropagation.after.mir
 pub fn f(mut a: usize) -> usize {
+    // CHECK-LABEL: fn f(
+    // CHECK: debug a => [[a:_.*]];
+    // CHECK: debug b => [[b:_.*]];
+    // CHECK: [[b]] = [[a]];
+    // CHECK: [[a]] = const 5_usize;
+    // CHECK: [[a]] = move [[b]];
+    // CHECK: id::<usize>(move [[a]])
     let b = a;
     a = 5;
     a = b;
diff --git a/tests/mir-opt/dest-prop/simple.rs b/tests/mir-opt/dest-prop/simple.rs
index 8e5d6340e56..833d49b8c46 100644
--- a/tests/mir-opt/dest-prop/simple.rs
+++ b/tests/mir-opt/dest-prop/simple.rs
@@ -1,9 +1,15 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too.
 //@ test-mir-pass: DestinationPropagation
 // EMIT_MIR simple.nrvo.DestinationPropagation.diff
 fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
+    // CHECK-LABEL: fn nrvo(
+    // CHECK: debug init => [[init:_.*]];
+    // CHECK: debug buf => [[buf:_.*]];
+    // CHECK: [[buf]] = [const 0_u8; 1024];
+    // CHECK-NOT: {{_.*}} = [[init]];
+    // CHECK: move [[init]](move {{_.*}})
+    // CHECK: {{_.*}} = [[buf]]
     let mut buf = [0; 1024];
     init(&mut buf);
     buf
diff --git a/tests/mir-opt/dest-prop/union.rs b/tests/mir-opt/dest-prop/union.rs
index 66fadd84712..4e6fb71bf75 100644
--- a/tests/mir-opt/dest-prop/union.rs
+++ b/tests/mir-opt/dest-prop/union.rs
@@ -8,6 +8,8 @@ fn val() -> u32 {
 
 // EMIT_MIR union.main.DestinationPropagation.diff
 fn main() {
+    // CHECK-LABEL: fn args(
+    // CHECK: {{_.*}} = Un { us: const 1_u32 };
     union Un {
         us: u32,
     }
diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
index 775a60f1c96..085c55caaa0 100644
--- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
+++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
@@ -64,9 +64,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     02 00 00 00 05 20 00 00                         │ ..... ..
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
index c4b57579943..798b7c10fe8 100644
--- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
+++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
@@ -64,9 +64,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 16, align: 8) {
-+     02 00 00 00 00 00 00 00 05 20 00 00 00 00 00 00 │ ......... ......
   }
++ 
++ ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/enum_opt.rs b/tests/mir-opt/enum_opt.rs
index 2cc5df84d6b..e42be8ac06d 100644
--- a/tests/mir-opt/enum_opt.rs
+++ b/tests/mir-opt/enum_opt.rs
@@ -1,7 +1,7 @@
 // skip-filecheck
 //@ test-mir-pass: EnumSizeOpt
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
-//@ compile-flags: -Zunsound-mir-opts
+//@ compile-flags: -Zunsound-mir-opts -Zdump-mir-exclude-alloc-bytes
 
 #![feature(arbitrary_enum_discriminant, repr128)]
 
diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
index f7d0d1fb56c..a04829af4b5 100644
--- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
+++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
@@ -64,9 +64,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     05 20 00 00 01 00 00 00                         │ . ......
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
index 15f1bd0df51..f5521a1e22a 100644
--- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
+++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
@@ -64,9 +64,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 16, align: 8) {
-+     05 20 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ . ..............
   }
++ 
++ ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
index 5bf22af6ae8..0e3f2459fae 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
@@ -140,9 +140,7 @@
           _0 = const ();
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 16, align: 8) {
-+     00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░
   }
++ 
++ ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
index 18d2029e445..2873d7ef0ab 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
@@ -140,9 +140,7 @@
           _0 = const ();
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 16, align: 8) {
-+     00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░
   }
++ 
++ ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
index 0c49e706c9e..b5c0cee7846 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:614:19: 614:21};
+      let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:614:19: 614:21};
+      let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:614:19: 614:21};
+              let _7: {closure@$DIR/gvn.rs:615:19: 615:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:614:19: 614:21};
+-         _7 = {closure@$DIR/gvn.rs:615:19: 615:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
index e5f865b74b9..7bc6573c13d 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:614:19: 614:21};
+      let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:614:19: 614:21};
+      let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:614:19: 614:21};
+              let _7: {closure@$DIR/gvn.rs:615:19: 615:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:614:19: 614:21};
+-         _7 = {closure@$DIR/gvn.rs:615:19: 615:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:614:19: 614:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff b/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff
index f853942bbb6..e84f91e495d 100644
--- a/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff
@@ -13,7 +13,5 @@
       }
   }
   
-  ALLOC0 (static: A, size: 2, align: 1) {
-      00 __                                           │ .░
-  }
+  ALLOC0 (static: A, size: 2, align: 1) { .. }
   
diff --git a/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff b/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff
index f853942bbb6..e84f91e495d 100644
--- a/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff
@@ -13,7 +13,5 @@
       }
   }
   
-  ALLOC0 (static: A, size: 2, align: 1) {
-      00 __                                           │ .░
-  }
+  ALLOC0 (static: A, size: 2, align: 1) { .. }
   
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index c7fae0bd081..430f979fec7 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -1,4 +1,5 @@
 //@ test-mir-pass: GVN
+//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //@ only-64bit
 
diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
index 07c4c7663c1..3eed0473f7f 100644
--- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-abort.diff
@@ -176,13 +176,9 @@
 +         nop;
           return;
       }
-+ }
+  }
 + 
-+ ALLOC1 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................
-+ }
++ ALLOC1 (size: 16, align: 8) { .. }
 + 
-+ ALLOC0 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
-  }
++ ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
index df0f93f1077..9a6e255a872 100644
--- a/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.wide_ptr_integer.GVN.panic-unwind.diff
@@ -176,13 +176,9 @@
 +         nop;
           return;
       }
-+ }
+  }
 + 
-+ ALLOC1 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................
-+ }
++ ALLOC1 (size: 16, align: 8) { .. }
 + 
-+ ALLOC0 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................
-  }
++ ALLOC0 (size: 16, align: 8) { .. }
   
diff --git a/tests/mir-opt/issue_72181.bar.built.after.mir b/tests/mir-opt/issue_72181.bar.built.after.mir
index 3ab9152f8bb..b6cc7d22195 100644
--- a/tests/mir-opt/issue_72181.bar.built.after.mir
+++ b/tests/mir-opt/issue_72181.bar.built.after.mir
@@ -19,8 +19,4 @@ fn bar(_1: [(Never, u32); 1]) -> u32 {
         FakeRead(ForMatchedPlace(None), _1);
         unreachable;
     }
-
-    bb2: {
-        goto -> bb1;
-    }
 }
diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir
index fa101512d72..89d351d5172 100644
--- a/tests/mir-opt/issue_72181.main.built.after.mir
+++ b/tests/mir-opt/issue_72181.main.built.after.mir
@@ -20,7 +20,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb7];
+        _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb5];
     }
 
     bb1: {
@@ -40,7 +40,7 @@ fn main() -> () {
         _6 = const 0_usize;
         _7 = Len(_2);
         _8 = Lt(_6, _7);
-        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb4, unwind: bb7];
+        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb5];
     }
 
     bb2: {
@@ -49,10 +49,6 @@ fn main() -> () {
     }
 
     bb3: {
-        goto -> bb2;
-    }
-
-    bb4: {
         _5 = (_2[_6].0: u64);
         PlaceMention(_5);
         StorageDead(_6);
@@ -62,16 +58,12 @@ fn main() -> () {
         return;
     }
 
-    bb5: {
+    bb4: {
         FakeRead(ForMatchedPlace(None), _5);
         unreachable;
     }
 
-    bb6: {
-        goto -> bb5;
-    }
-
-    bb7 (cleanup): {
+    bb5 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/issue_72181_1.f.built.after.mir b/tests/mir-opt/issue_72181_1.f.built.after.mir
index 674a4013fe7..89da9a80113 100644
--- a/tests/mir-opt/issue_72181_1.f.built.after.mir
+++ b/tests/mir-opt/issue_72181_1.f.built.after.mir
@@ -6,15 +6,11 @@ fn f(_1: Void) -> ! {
 
     bb0: {
         PlaceMention(_1);
-        goto -> bb1;
-    }
-
-    bb1: {
         FakeRead(ForMatchedPlace(None), _1);
         unreachable;
     }
 
-    bb2: {
+    bb1: {
         return;
     }
 }
diff --git a/tests/mir-opt/issue_91633.bar.built.after.mir b/tests/mir-opt/issue_91633.bar.built.after.mir
index 3dcdcab9dea..53829588a1b 100644
--- a/tests/mir-opt/issue_91633.bar.built.after.mir
+++ b/tests/mir-opt/issue_91633.bar.built.after.mir
@@ -12,7 +12,7 @@ fn bar(_1: Box<[T]>) -> () {
         StorageLive(_2);
         StorageLive(_3);
         _3 = &(*_1);
-        _2 = <[T] as Index<usize>>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb5];
+        _2 = <[T] as Index<usize>>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb4];
     }
 
     bb1: {
@@ -20,7 +20,7 @@ fn bar(_1: Box<[T]>) -> () {
         PlaceMention((*_2));
         StorageDead(_2);
         _0 = const ();
-        drop(_1) -> [return: bb4, unwind: bb6];
+        drop(_1) -> [return: bb3, unwind: bb5];
     }
 
     bb2: {
@@ -29,18 +29,14 @@ fn bar(_1: Box<[T]>) -> () {
     }
 
     bb3: {
-        goto -> bb2;
-    }
-
-    bb4: {
         return;
     }
 
-    bb5 (cleanup): {
-        drop(_1) -> [return: bb6, unwind terminate(cleanup)];
+    bb4 (cleanup): {
+        drop(_1) -> [return: bb5, unwind terminate(cleanup)];
     }
 
-    bb6 (cleanup): {
+    bb5 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/issue_91633.hey.built.after.mir b/tests/mir-opt/issue_91633.hey.built.after.mir
index e782f4d1a23..a537e509996 100644
--- a/tests/mir-opt/issue_91633.hey.built.after.mir
+++ b/tests/mir-opt/issue_91633.hey.built.after.mir
@@ -14,7 +14,7 @@ fn hey(_1: &[T]) -> () {
         StorageLive(_3);
         StorageLive(_4);
         _4 = &(*_1);
-        _3 = <[T] as Index<usize>>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb4];
+        _3 = <[T] as Index<usize>>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb3];
     }
 
     bb1: {
@@ -32,11 +32,7 @@ fn hey(_1: &[T]) -> () {
         unreachable;
     }
 
-    bb3: {
-        goto -> bb2;
-    }
-
-    bb4 (cleanup): {
+    bb3 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
index b7a054b5d54..72e7f4794f9 100644
--- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
@@ -67,7 +67,7 @@ fn main() -> () {
         StorageLive(_2);
         StorageLive(_3);
         StorageLive(_4);
-        _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb25];
+        _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23];
     }
 
     bb1: {
@@ -91,7 +91,7 @@ fn main() -> () {
         _11 = &(*_8);
         StorageLive(_12);
         _12 = &(*_9);
-        _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb4, unwind: bb25];
+        _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23];
     }
 
     bb2: {
@@ -100,24 +100,20 @@ fn main() -> () {
     }
 
     bb3: {
-        goto -> bb2;
+        switchInt(move _10) -> [0: bb5, otherwise: bb4];
     }
 
     bb4: {
-        switchInt(move _10) -> [0: bb6, otherwise: bb5];
-    }
-
-    bb5: {
         StorageDead(_12);
         StorageDead(_11);
-        goto -> bb10;
+        goto -> bb9;
     }
 
-    bb6: {
-        goto -> bb7;
+    bb5: {
+        goto -> bb6;
     }
 
-    bb7: {
+    bb6: {
         StorageDead(_12);
         StorageDead(_11);
         StorageLive(_14);
@@ -136,10 +132,10 @@ fn main() -> () {
         _19 = &(*_20);
         StorageLive(_21);
         _21 = Option::<Arguments<'_>>::None;
-        _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb25;
+        _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23;
     }
 
-    bb8: {
+    bb7: {
         StorageDead(_21);
         StorageDead(_19);
         StorageDead(_17);
@@ -151,23 +147,23 @@ fn main() -> () {
         unreachable;
     }
 
-    bb9: {
-        goto -> bb11;
+    bb8: {
+        goto -> bb10;
     }
 
-    bb10: {
+    bb9: {
         _1 = const ();
-        goto -> bb11;
+        goto -> bb10;
     }
 
-    bb11: {
+    bb10: {
         StorageDead(_10);
         StorageDead(_9);
         StorageDead(_8);
-        goto -> bb12;
+        goto -> bb11;
     }
 
-    bb12: {
+    bb11: {
         StorageDead(_7);
         StorageDead(_6);
         StorageDead(_4);
@@ -177,10 +173,10 @@ fn main() -> () {
         StorageLive(_23);
         StorageLive(_24);
         StorageLive(_25);
-        _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb13, unwind: bb25];
+        _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23];
     }
 
-    bb13: {
+    bb12: {
         _24 = &_25;
         StorageLive(_26);
         StorageLive(_27);
@@ -199,33 +195,29 @@ fn main() -> () {
         _31 = &(*_28);
         StorageLive(_32);
         _32 = &(*_29);
-        _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb16, unwind: bb25];
+        _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23];
     }
 
-    bb14: {
+    bb13: {
         FakeRead(ForMatchedPlace(None), _23);
         unreachable;
     }
 
-    bb15: {
-        goto -> bb14;
-    }
-
-    bb16: {
-        switchInt(move _30) -> [0: bb18, otherwise: bb17];
+    bb14: {
+        switchInt(move _30) -> [0: bb16, otherwise: bb15];
     }
 
-    bb17: {
+    bb15: {
         StorageDead(_32);
         StorageDead(_31);
-        goto -> bb22;
+        goto -> bb20;
     }
 
-    bb18: {
-        goto -> bb19;
+    bb16: {
+        goto -> bb17;
     }
 
-    bb19: {
+    bb17: {
         StorageDead(_32);
         StorageDead(_31);
         StorageLive(_34);
@@ -244,10 +236,10 @@ fn main() -> () {
         _39 = &(*_40);
         StorageLive(_41);
         _41 = Option::<Arguments<'_>>::None;
-        _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb25;
+        _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23;
     }
 
-    bb20: {
+    bb18: {
         StorageDead(_41);
         StorageDead(_39);
         StorageDead(_37);
@@ -259,23 +251,23 @@ fn main() -> () {
         unreachable;
     }
 
-    bb21: {
-        goto -> bb23;
+    bb19: {
+        goto -> bb21;
     }
 
-    bb22: {
+    bb20: {
         _22 = const ();
-        goto -> bb23;
+        goto -> bb21;
     }
 
-    bb23: {
+    bb21: {
         StorageDead(_30);
         StorageDead(_29);
         StorageDead(_28);
-        goto -> bb24;
+        goto -> bb22;
     }
 
-    bb24: {
+    bb22: {
         StorageDead(_27);
         StorageDead(_25);
         StorageDead(_23);
@@ -284,7 +276,7 @@ fn main() -> () {
         return;
     }
 
-    bb25 (cleanup): {
+    bb23 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
index b7a054b5d54..72e7f4794f9 100644
--- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
@@ -67,7 +67,7 @@ fn main() -> () {
         StorageLive(_2);
         StorageLive(_3);
         StorageLive(_4);
-        _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb25];
+        _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23];
     }
 
     bb1: {
@@ -91,7 +91,7 @@ fn main() -> () {
         _11 = &(*_8);
         StorageLive(_12);
         _12 = &(*_9);
-        _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb4, unwind: bb25];
+        _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23];
     }
 
     bb2: {
@@ -100,24 +100,20 @@ fn main() -> () {
     }
 
     bb3: {
-        goto -> bb2;
+        switchInt(move _10) -> [0: bb5, otherwise: bb4];
     }
 
     bb4: {
-        switchInt(move _10) -> [0: bb6, otherwise: bb5];
-    }
-
-    bb5: {
         StorageDead(_12);
         StorageDead(_11);
-        goto -> bb10;
+        goto -> bb9;
     }
 
-    bb6: {
-        goto -> bb7;
+    bb5: {
+        goto -> bb6;
     }
 
-    bb7: {
+    bb6: {
         StorageDead(_12);
         StorageDead(_11);
         StorageLive(_14);
@@ -136,10 +132,10 @@ fn main() -> () {
         _19 = &(*_20);
         StorageLive(_21);
         _21 = Option::<Arguments<'_>>::None;
-        _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb25;
+        _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23;
     }
 
-    bb8: {
+    bb7: {
         StorageDead(_21);
         StorageDead(_19);
         StorageDead(_17);
@@ -151,23 +147,23 @@ fn main() -> () {
         unreachable;
     }
 
-    bb9: {
-        goto -> bb11;
+    bb8: {
+        goto -> bb10;
     }
 
-    bb10: {
+    bb9: {
         _1 = const ();
-        goto -> bb11;
+        goto -> bb10;
     }
 
-    bb11: {
+    bb10: {
         StorageDead(_10);
         StorageDead(_9);
         StorageDead(_8);
-        goto -> bb12;
+        goto -> bb11;
     }
 
-    bb12: {
+    bb11: {
         StorageDead(_7);
         StorageDead(_6);
         StorageDead(_4);
@@ -177,10 +173,10 @@ fn main() -> () {
         StorageLive(_23);
         StorageLive(_24);
         StorageLive(_25);
-        _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb13, unwind: bb25];
+        _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23];
     }
 
-    bb13: {
+    bb12: {
         _24 = &_25;
         StorageLive(_26);
         StorageLive(_27);
@@ -199,33 +195,29 @@ fn main() -> () {
         _31 = &(*_28);
         StorageLive(_32);
         _32 = &(*_29);
-        _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb16, unwind: bb25];
+        _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23];
     }
 
-    bb14: {
+    bb13: {
         FakeRead(ForMatchedPlace(None), _23);
         unreachable;
     }
 
-    bb15: {
-        goto -> bb14;
-    }
-
-    bb16: {
-        switchInt(move _30) -> [0: bb18, otherwise: bb17];
+    bb14: {
+        switchInt(move _30) -> [0: bb16, otherwise: bb15];
     }
 
-    bb17: {
+    bb15: {
         StorageDead(_32);
         StorageDead(_31);
-        goto -> bb22;
+        goto -> bb20;
     }
 
-    bb18: {
-        goto -> bb19;
+    bb16: {
+        goto -> bb17;
     }
 
-    bb19: {
+    bb17: {
         StorageDead(_32);
         StorageDead(_31);
         StorageLive(_34);
@@ -244,10 +236,10 @@ fn main() -> () {
         _39 = &(*_40);
         StorageLive(_41);
         _41 = Option::<Arguments<'_>>::None;
-        _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb25;
+        _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23;
     }
 
-    bb20: {
+    bb18: {
         StorageDead(_41);
         StorageDead(_39);
         StorageDead(_37);
@@ -259,23 +251,23 @@ fn main() -> () {
         unreachable;
     }
 
-    bb21: {
-        goto -> bb23;
+    bb19: {
+        goto -> bb21;
     }
 
-    bb22: {
+    bb20: {
         _22 = const ();
-        goto -> bb23;
+        goto -> bb21;
     }
 
-    bb23: {
+    bb21: {
         StorageDead(_30);
         StorageDead(_29);
         StorageDead(_28);
-        goto -> bb24;
+        goto -> bb22;
     }
 
-    bb24: {
+    bb22: {
         StorageDead(_27);
         StorageDead(_25);
         StorageDead(_23);
@@ -284,7 +276,7 @@ fn main() -> () {
         return;
     }
 
-    bb25 (cleanup): {
+    bb23 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff
new file mode 100644
index 00000000000..0c8e04a1e74
--- /dev/null
+++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff
@@ -0,0 +1,56 @@
+- // MIR for `aggregate_copy` before JumpThreading
++ // MIR for `aggregate_copy` after JumpThreading
+  
+  fn aggregate_copy() -> u32 {
+      let mut _0: u32;
+      let _1: (u32, u32);
+      let mut _4: bool;
+      let mut _5: u32;
+      scope 1 {
+          debug a => _1;
+          let _2: (u32, u32);
+          scope 2 {
+              debug b => _2;
+              let _3: u32;
+              scope 3 {
+                  debug c => _3;
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const aggregate_copy::Foo;
+          StorageLive(_2);
+          _2 = _1;
+          StorageLive(_3);
+          _3 = (_2.1: u32);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = _3;
+          _4 = Eq(move _5, const 2_u32);
+-         switchInt(move _4) -> [0: bb2, otherwise: bb1];
++         goto -> bb2;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          _0 = (_2.0: u32);
+          goto -> bb3;
+      }
+  
+      bb2: {
+          StorageDead(_5);
+          _0 = const 13_u32;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_4);
+          StorageDead(_3);
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff
new file mode 100644
index 00000000000..0c8e04a1e74
--- /dev/null
+++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff
@@ -0,0 +1,56 @@
+- // MIR for `aggregate_copy` before JumpThreading
++ // MIR for `aggregate_copy` after JumpThreading
+  
+  fn aggregate_copy() -> u32 {
+      let mut _0: u32;
+      let _1: (u32, u32);
+      let mut _4: bool;
+      let mut _5: u32;
+      scope 1 {
+          debug a => _1;
+          let _2: (u32, u32);
+          scope 2 {
+              debug b => _2;
+              let _3: u32;
+              scope 3 {
+                  debug c => _3;
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const aggregate_copy::Foo;
+          StorageLive(_2);
+          _2 = _1;
+          StorageLive(_3);
+          _3 = (_2.1: u32);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = _3;
+          _4 = Eq(move _5, const 2_u32);
+-         switchInt(move _4) -> [0: bb2, otherwise: bb1];
++         goto -> bb2;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          _0 = (_2.0: u32);
+          goto -> bb3;
+      }
+  
+      bb2: {
+          StorageDead(_5);
+          _0 = const 13_u32;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_4);
+          StorageDead(_3);
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs
index b4c13371680..de290c1ef44 100644
--- a/tests/mir-opt/jump_threading.rs
+++ b/tests/mir-opt/jump_threading.rs
@@ -506,6 +506,21 @@ fn assume(a: u8, b: bool) -> u8 {
     }
 }
 
+/// Verify that jump threading succeeds seeing through copies of aggregates.
+fn aggregate_copy() -> u32 {
+    // CHECK-LABEL: fn aggregate_copy(
+    // CHECK-NOT: switchInt(
+
+    const Foo: (u32, u32) = (5, 3);
+
+    let a = Foo;
+    // This copies a tuple, we want to ensure that the threading condition on `b.1` propagates to a
+    // condition on `a.1`.
+    let b = a;
+    let c = b.1;
+    if c == 2 { b.0 } else { 13 }
+}
+
 fn main() {
     // CHECK-LABEL: fn main(
     too_complex(Ok(0));
@@ -534,3 +549,4 @@ fn main() {
 // EMIT_MIR jump_threading.disappearing_bb.JumpThreading.diff
 // EMIT_MIR jump_threading.aggregate.JumpThreading.diff
 // EMIT_MIR jump_threading.assume.JumpThreading.diff
+// EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 209f0d09c29..4f29e5244d7 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -32,25 +32,33 @@
   
       bb0: {
           PlaceMention(_2);
--         switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1];
+-         switchInt((_2.0: bool)) -> [0: bb2, otherwise: bb1];
 +         switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1];
       }
   
       bb1: {
--         switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2];
+-         switchInt((_2.1: bool)) -> [0: bb4, otherwise: bb3];
 +         switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2];
       }
   
       bb2: {
--         switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
+-         falseEdge -> [real: bb8, imaginary: bb1];
 +         switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
       }
   
       bb3: {
--         falseEdge -> [real: bb20, imaginary: bb4];
+-         switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5];
 -     }
 - 
 -     bb4: {
+-         falseEdge -> [real: bb13, imaginary: bb3];
+-     }
+- 
+-     bb5: {
+-         falseEdge -> [real: bb20, imaginary: bb6];
+-     }
+- 
+-     bb6: {
           StorageLive(_15);
           _15 = (_2.1: bool);
           StorageLive(_16);
@@ -59,14 +67,6 @@
 +         goto -> bb16;
       }
   
--     bb5: {
--         falseEdge -> [real: bb13, imaginary: bb2];
--     }
-- 
--     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb1];
--     }
-- 
 -     bb7: {
 +     bb4: {
           _0 = const 1_i32;
@@ -184,7 +184,7 @@
           StorageDead(_12);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb2, imaginary: bb2];
+-         falseEdge -> [real: bb3, imaginary: bb3];
 +         goto -> bb2;
       }
   
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 209f0d09c29..4f29e5244d7 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -32,25 +32,33 @@
   
       bb0: {
           PlaceMention(_2);
--         switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1];
+-         switchInt((_2.0: bool)) -> [0: bb2, otherwise: bb1];
 +         switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1];
       }
   
       bb1: {
--         switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2];
+-         switchInt((_2.1: bool)) -> [0: bb4, otherwise: bb3];
 +         switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2];
       }
   
       bb2: {
--         switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
+-         falseEdge -> [real: bb8, imaginary: bb1];
 +         switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
       }
   
       bb3: {
--         falseEdge -> [real: bb20, imaginary: bb4];
+-         switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5];
 -     }
 - 
 -     bb4: {
+-         falseEdge -> [real: bb13, imaginary: bb3];
+-     }
+- 
+-     bb5: {
+-         falseEdge -> [real: bb20, imaginary: bb6];
+-     }
+- 
+-     bb6: {
           StorageLive(_15);
           _15 = (_2.1: bool);
           StorageLive(_16);
@@ -59,14 +67,6 @@
 +         goto -> bb16;
       }
   
--     bb5: {
--         falseEdge -> [real: bb13, imaginary: bb2];
--     }
-- 
--     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb1];
--     }
-- 
 -     bb7: {
 +     bb4: {
           _0 = const 1_i32;
@@ -184,7 +184,7 @@
           StorageDead(_12);
           StorageDead(_8);
           StorageDead(_6);
--         falseEdge -> [real: bb2, imaginary: bb2];
+-         falseEdge -> [real: bb3, imaginary: bb3];
 +         goto -> bb2;
       }
   
diff --git a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir
index 56edd38a6da..e357e785e33 100644
--- a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir
@@ -18,24 +18,24 @@ fn shortcut_second_or() -> () {
         _1 = (move _2, const 0_i32);
         StorageDead(_2);
         PlaceMention(_1);
-        switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb4, otherwise: bb2];
+        switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb2, otherwise: bb1];
     }
 
     bb1: {
-        _0 = const ();
-        goto -> bb14;
+        switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb4, otherwise: bb3];
     }
 
     bb2: {
-        switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb3, otherwise: bb1];
+        switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb3];
     }
 
     bb3: {
-        switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb1];
+        _0 = const ();
+        goto -> bb14;
     }
 
     bb4: {
-        switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb1];
+        switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb3];
     }
 
     bb5: {
@@ -43,7 +43,7 @@ fn shortcut_second_or() -> () {
     }
 
     bb6: {
-        falseEdge -> [real: bb11, imaginary: bb2];
+        falseEdge -> [real: bb11, imaginary: bb1];
     }
 
     bb7: {
@@ -51,7 +51,7 @@ fn shortcut_second_or() -> () {
     }
 
     bb8: {
-        falseEdge -> [real: bb13, imaginary: bb1];
+        falseEdge -> [real: bb13, imaginary: bb3];
     }
 
     bb9: {
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
index 2f34a62b3d1..45b8d89c0f4 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
@@ -61,9 +61,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     04 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
index da7add371a5..e6ee1e6f9a3 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
@@ -61,9 +61,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     04 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
index 2f34a62b3d1..45b8d89c0f4 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
@@ -61,9 +61,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     04 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
index da7add371a5..e6ee1e6f9a3 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
@@ -61,9 +61,7 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     04 00 00 00 00 __ __ __                         │ .....░░░
   }
++ 
++ ALLOC0 (size: 8, align: 4) { .. }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs
index de5e2d5c312..44b4b0ad888 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs
@@ -1,6 +1,6 @@
 // skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-//@ compile-flags: -C overflow-checks=on
+//@ compile-flags: -C overflow-checks=on -Zdump-mir-exclude-alloc-bytes
 
 struct Point {
     x: u32,
diff --git a/tests/run-make/env-dep-info/Makefile b/tests/run-make/env-dep-info/Makefile
deleted file mode 100644
index bc0ffc2df1e..00000000000
--- a/tests/run-make/env-dep-info/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-include ../tools.mk
-
-# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC`
-# instead of hardcoding them everywhere they're needed.
-ifeq ($(IS_MUSL_HOST),1)
-ADDITIONAL_ARGS := $(RUSTFLAGS)
-endif
-
-all:
-	EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs
-	$(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d
-	$(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d
-	$(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d
-	$(CGREP) "# env-dep:ESCAPE\nESCAPE\\" < $(TMPDIR)/main.d
-	# Proc macro
-	$(BARE_RUSTC) $(ADDITIONAL_ARGS) --out-dir $(TMPDIR) macro_def.rs
-	EXISTING_PROC_MACRO_ENV=1 $(RUSTC) --emit dep-info macro_use.rs
-	$(CGREP) "# env-dep:EXISTING_PROC_MACRO_ENV=1" < $(TMPDIR)/macro_use.d
-	$(CGREP) "# env-dep:NONEXISTENT_PROC_MACEO_ENV" < $(TMPDIR)/macro_use.d
diff --git a/tests/run-make/env-dep-info/correct_macro.d b/tests/run-make/env-dep-info/correct_macro.d
new file mode 100644
index 00000000000..edfe0e63202
--- /dev/null
+++ b/tests/run-make/env-dep-info/correct_macro.d
@@ -0,0 +1,6 @@
+macro_use.d: macro_use.rs
+
+macro_use.rs:
+
+# env-dep:EXISTING_PROC_MACRO_ENV=1
+# env-dep:NONEXISTENT_PROC_MACEO_ENV
diff --git a/tests/run-make/env-dep-info/correct_main.d b/tests/run-make/env-dep-info/correct_main.d
new file mode 100644
index 00000000000..ef89729841d
--- /dev/null
+++ b/tests/run-make/env-dep-info/correct_main.d
@@ -0,0 +1,8 @@
+main.d: main.rs
+
+main.rs:
+
+# env-dep:ESCAPE\nESCAPE\\
+# env-dep:EXISTING_ENV=1
+# env-dep:EXISTING_OPT_ENV=1
+# env-dep:NONEXISTENT_OPT_ENV
diff --git a/tests/run-make/env-dep-info/rmake.rs b/tests/run-make/env-dep-info/rmake.rs
new file mode 100644
index 00000000000..5b51a5476f4
--- /dev/null
+++ b/tests/run-make/env-dep-info/rmake.rs
@@ -0,0 +1,21 @@
+// Inside dep-info emit files, #71858 made it so all accessed environment
+// variables are usefully printed. This test checks that this feature works
+// as intended by checking if the environment variables used in compilation
+// appear in the output dep-info files.
+// See https://github.com/rust-lang/rust/issues/40364
+
+use run_make_support::{diff, rustc};
+
+fn main() {
+    rustc()
+        .env("EXISTING_ENV", "1")
+        .env("EXISTING_OPT_ENV", "1")
+        .emit("dep-info")
+        .input("main.rs")
+        .run();
+    diff().expected_file("correct_main.d").actual_file("main.d").run();
+    // Procedural macro
+    rustc().input("macro_def.rs").run();
+    rustc().env("EXISTING_PROC_MACRO_ENV", "1").emit("dep-info").input("macro_use.rs").run();
+    diff().expected_file("correct_macro.d").actual_file("macro_use.d").run();
+}
diff --git a/tests/run-make/extra-filename-with-temp-outputs/Makefile b/tests/run-make/extra-filename-with-temp-outputs/Makefile
deleted file mode 100644
index 64745bef5b8..00000000000
--- a/tests/run-make/extra-filename-with-temp-outputs/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) -C extra-filename=bar foo.rs -C save-temps
-	rm $(TMPDIR)/foobar.foo*0.rcgu.o
-	rm $(TMPDIR)/$(call BIN,foobar)
diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs
new file mode 100644
index 00000000000..c39e397a7cb
--- /dev/null
+++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs
@@ -0,0 +1,21 @@
+// In order to prevent temporary files from overwriting each other in parallel
+// compilation, rustc was changed to mix an extra filename with temporary
+// outputs. However, as this is a similar behavior with the codegen flag
+// -C extra-filename, this test checks that the manually passed flag
+// is not overwritten by this feature, and that the output files
+// are named as expected.
+// See https://github.com/rust-lang/rust/pull/15686
+
+use run_make_support::{
+    bin_name, cwd, fs_wrapper, has_prefix, has_suffix, rustc, shallow_find_files,
+};
+
+fn main() {
+    rustc().extra_filename("bar").input("foo.rs").arg("-Csave-temps").run();
+    let object_files = shallow_find_files(cwd(), |path| {
+        has_prefix(path, "foobar.foo") && has_suffix(path, "0.rcgu.o")
+    });
+    let object_file = object_files.get(0).unwrap();
+    fs_wrapper::remove_file(object_file);
+    fs_wrapper::remove_file(bin_name("foobar"));
+}
diff --git a/tests/run-make/issue-83045/a.rs b/tests/run-make/ice-dep-cannot-find-dep/a.rs
index 66d9f758e9d..66d9f758e9d 100644
--- a/tests/run-make/issue-83045/a.rs
+++ b/tests/run-make/ice-dep-cannot-find-dep/a.rs
diff --git a/tests/run-make/issue-83045/b.rs b/tests/run-make/ice-dep-cannot-find-dep/b.rs
index f4876cfa457..f4876cfa457 100644
--- a/tests/run-make/issue-83045/b.rs
+++ b/tests/run-make/ice-dep-cannot-find-dep/b.rs
diff --git a/tests/run-make/issue-83045/c.rs b/tests/run-make/ice-dep-cannot-find-dep/c.rs
index e0c4525499e..e0c4525499e 100644
--- a/tests/run-make/issue-83045/c.rs
+++ b/tests/run-make/ice-dep-cannot-find-dep/c.rs
diff --git a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs
new file mode 100644
index 00000000000..33c755bddd7
--- /dev/null
+++ b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs
@@ -0,0 +1,38 @@
+// This test case creates a situation where the crate loader would run
+// into an ICE (internal compiler error) when confronted with an invalid setup where it cannot
+// find the dependency of a direct dependency.
+//
+// The test case makes sure that the compiler produces the expected
+// error message but does not ICE immediately after.
+//
+// See https://github.com/rust-lang/rust/issues/83045
+
+//@ only-x86_64
+//@ only-linux
+// Reason: This is a platform-independent issue, no need to waste time testing
+// everywhere.
+
+// NOTE: We use `bare_rustc` below so that the compiler can't find liba.rlib
+//       If we used `rustc` the additional '-L rmake_out' option would allow rustc to
+//       actually find the crate.
+
+use run_make_support::{bare_rustc, fs_wrapper, rust_lib_name, rustc};
+
+fn main() {
+    rustc().crate_name("a").crate_type("rlib").input("a.rs").arg("--verbose").run();
+    rustc()
+        .crate_name("b")
+        .crate_type("rlib")
+        .extern_("a", rust_lib_name("a"))
+        .input("b.rs")
+        .arg("--verbose")
+        .run();
+    bare_rustc()
+        .extern_("b", rust_lib_name("b"))
+        .crate_type("rlib")
+        .edition("2018")
+        .input("c.rs")
+        .run_fail()
+        .assert_stderr_contains("E0463")
+        .assert_stderr_not_contains("internal compiler error");
+}
diff --git a/tests/run-make/issue-83045/Makefile b/tests/run-make/issue-83045/Makefile
deleted file mode 100644
index b76e184b610..00000000000
--- a/tests/run-make/issue-83045/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-include ../tools.mk
-
-# This test case creates a situation where the crate loader would run
-# into an ICE when confronted with an invalid setup where it cannot
-# find the dependency of a direct dependency.
-#
-# The test case makes sure that the compiler produces the expected
-# error message but does not ICE immediately after.
-#
-# See https://github.com/rust-lang/rust/issues/83045
-
-# This is a platform-independent issue, no need to waste time testing
-# everywhere.
-# only-x86_64
-# only-linux
-
-# NOTE: We use BARE_RUSTC below so that the compiler can't find liba.rlib
-#       If we used RUSTC the additional '-L TMPDIR' option would allow rustc to
-#       actually find the crate.
-#
-#       We check that we get the expected error message
-#       But that we do not get an ICE
-
-all:
-	$(RUSTC) --crate-name=a --crate-type=rlib a.rs --verbose
-	$(RUSTC) --crate-name=b --crate-type=rlib --extern a=$(TMPDIR)/liba.rlib b.rs --verbose
-	$(BARE_RUSTC) --out-dir $(TMPDIR) \
-	              --extern b=$(TMPDIR)/libb.rlib \
-				  --crate-type=rlib \
-				  --edition=2018 \
-				  c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0
-	$(CGREP) E0463 < $(TMPDIR)/output.txt
-	$(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt
diff --git a/tests/run-make/issue-85019-moved-src-dir/Makefile b/tests/run-make/issue-85019-moved-src-dir/Makefile
deleted file mode 100644
index dec289058f9..00000000000
--- a/tests/run-make/issue-85019-moved-src-dir/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-include ../tools.mk
-
-INCR=$(TMPDIR)/incr
-FIRST_SRC=$(TMPDIR)/first_src
-SECOND_SRC=$(TMPDIR)/second_src
-
-# ignore-none no-std is not supported
-# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for 'std'
-
-# Tests that we don't get an ICE when the working directory
-# (but not the build directory!) changes between compilation
-# sessions
-
-all:
-	mkdir $(INCR)
-	# Build from 'FIRST_SRC'
-	mkdir $(FIRST_SRC)
-	cp my_lib.rs $(FIRST_SRC)/my_lib.rs
-	cp main.rs $(FIRST_SRC)/main.rs
-	cd $(FIRST_SRC) && \
-		$(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs --target $(TARGET) && \
-		$(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs --target $(TARGET)
-	# Build from 'SECOND_SRC', keeping the output directory and incremental directory
-	# the same
-	mv $(FIRST_SRC) $(SECOND_SRC)
-	cd $(SECOND_SRC) && \
-		$(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs --target $(TARGET) && \
-		$(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs --target $(TARGET)
diff --git a/tests/run-make/issue-85019-moved-src-dir/main.rs b/tests/run-make/moved-src-dir-fingerprint-ice/main.rs
index 543559a5c53..543559a5c53 100644
--- a/tests/run-make/issue-85019-moved-src-dir/main.rs
+++ b/tests/run-make/moved-src-dir-fingerprint-ice/main.rs
diff --git a/tests/run-make/issue-85019-moved-src-dir/my_lib.rs b/tests/run-make/moved-src-dir-fingerprint-ice/my_lib.rs
index 432875739af..432875739af 100644
--- a/tests/run-make/issue-85019-moved-src-dir/my_lib.rs
+++ b/tests/run-make/moved-src-dir-fingerprint-ice/my_lib.rs
diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs
new file mode 100644
index 00000000000..c6426029989
--- /dev/null
+++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs
@@ -0,0 +1,38 @@
+// A SourceFile created during compilation may have a relative
+// path (e.g. if rustc itself is invoked with a relative path).
+// When we write out crate metadata, we convert all relative paths
+// to absolute paths using the current working directory.
+// However, the working directory was previously not included in the crate hash.
+// This meant that the crate metadata could change while the crate
+// hash remained the same. Among other problems, this could cause a
+// fingerprint mismatch ICE, since incremental compilation uses
+// the crate metadata hash to determine if a foreign query is green.
+// This test checks that we don't get an ICE when the working directory
+// (but not the build directory!) changes between compilation
+// sessions.
+// See https://github.com/rust-lang/rust/issues/85019
+
+//@ ignore-none
+// Reason: no-std is not supported
+//@ ignore-nvptx64-nvidia-cuda
+// FIXME: can't find crate for 'std'
+
+use run_make_support::{fs_wrapper, rust_lib_name, rustc};
+
+fn main() {
+    fs_wrapper::create_dir("incr");
+    fs_wrapper::create_dir("first_src");
+    fs_wrapper::create_dir("output");
+    fs_wrapper::rename("my_lib.rs", "first_src/my_lib.rs");
+    fs_wrapper::rename("main.rs", "first_src/main.rs");
+    // Build from "first_src"
+    std::env::set_current_dir("first_src").unwrap();
+    rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run();
+    rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run();
+    std::env::set_current_dir("..").unwrap();
+    fs_wrapper::rename("first_src", "second_src");
+    std::env::set_current_dir("second_src").unwrap();
+    // Build from "second_src" - the output and incremental directory remain identical
+    rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run();
+    rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run();
+}
diff --git a/tests/run-make/rustc-macro-dep-files/Makefile b/tests/run-make/rustc-macro-dep-files/Makefile
deleted file mode 100644
index 76d713c4bb3..00000000000
--- a/tests/run-make/rustc-macro-dep-files/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-include ../tools.mk
-
-# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC`
-# instead of hardcoding them everywhere they're needed.
-ifeq ($(IS_MUSL_HOST),1)
-ADDITIONAL_ARGS := $(RUSTFLAGS)
-endif
-all:
-	$(BARE_RUSTC) $(ADDITIONAL_ARGS) foo.rs --out-dir $(TMPDIR)
-	$(RUSTC) bar.rs --target $(TARGET) --emit dep-info
-	$(CGREP) -v "proc-macro source" < $(TMPDIR)/bar.d
diff --git a/tests/run-make/rustc-macro-dep-files/correct.d b/tests/run-make/rustc-macro-dep-files/correct.d
new file mode 100644
index 00000000000..8cb708fff61
--- /dev/null
+++ b/tests/run-make/rustc-macro-dep-files/correct.d
@@ -0,0 +1,3 @@
+bar.d: bar.rs
+
+bar.rs:
diff --git a/tests/run-make/rustc-macro-dep-files/rmake.rs b/tests/run-make/rustc-macro-dep-files/rmake.rs
new file mode 100644
index 00000000000..bc02a04c9b8
--- /dev/null
+++ b/tests/run-make/rustc-macro-dep-files/rmake.rs
@@ -0,0 +1,14 @@
+// --emit dep-info used to print all macro-generated code it could
+// find as if it was part of a nonexistent file named "proc-macro source",
+// which is not a valid path. After this was fixed in #36776, this test checks
+// that macro code is not falsely seen as coming from a different file in dep-info.
+// See https://github.com/rust-lang/rust/issues/36625
+
+use run_make_support::{diff, rustc, target};
+
+fn main() {
+    rustc().input("foo.rs").run();
+    rustc().input("bar.rs").target(target()).emit("dep-info").run();
+    // The emitted file should not contain "proc-macro source".
+    diff().expected_file("correct.d").actual_file("bar.d").run();
+}
diff --git a/tests/run-make/wasm-abi/foo.rs b/tests/run-make/wasm-abi/foo.rs
deleted file mode 100644
index 0678eb3ff51..00000000000
--- a/tests/run-make/wasm-abi/foo.rs
+++ /dev/null
@@ -1,87 +0,0 @@
-#![crate_type = "cdylib"]
-#![deny(warnings)]
-#![feature(wasm_abi)]
-
-#[repr(C)]
-#[derive(PartialEq, Debug)]
-pub struct TwoI32 {
-    pub a: i32,
-    pub b: i32,
-}
-
-#[no_mangle]
-pub extern "wasm" fn return_two_i32() -> TwoI32 {
-    TwoI32 { a: 1, b: 2 }
-}
-
-#[repr(C)]
-#[derive(PartialEq, Debug)]
-pub struct TwoI64 {
-    pub a: i64,
-    pub b: i64,
-}
-
-#[no_mangle]
-pub extern "wasm" fn return_two_i64() -> TwoI64 {
-    TwoI64 { a: 3, b: 4 }
-}
-
-#[repr(C)]
-#[derive(PartialEq, Debug)]
-pub struct TwoF32 {
-    pub a: f32,
-    pub b: f32,
-}
-
-#[no_mangle]
-pub extern "wasm" fn return_two_f32() -> TwoF32 {
-    TwoF32 { a: 5., b: 6. }
-}
-
-#[repr(C)]
-#[derive(PartialEq, Debug)]
-pub struct TwoF64 {
-    pub a: f64,
-    pub b: f64,
-}
-
-#[no_mangle]
-pub extern "wasm" fn return_two_f64() -> TwoF64 {
-    TwoF64 { a: 7., b: 8. }
-}
-
-#[repr(C)]
-#[derive(PartialEq, Debug)]
-pub struct Mishmash {
-    pub a: f64,
-    pub b: f32,
-    pub c: i32,
-    pub d: i64,
-    pub e: TwoI32,
-}
-
-#[no_mangle]
-pub extern "wasm" fn return_mishmash() -> Mishmash {
-    Mishmash { a: 9., b: 10., c: 11, d: 12, e: TwoI32 { a: 13, b: 14 } }
-}
-
-#[link(wasm_import_module = "host")]
-extern "wasm" {
-    fn two_i32() -> TwoI32;
-    fn two_i64() -> TwoI64;
-    fn two_f32() -> TwoF32;
-    fn two_f64() -> TwoF64;
-    fn mishmash() -> Mishmash;
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn call_imports() {
-    assert_eq!(two_i32(), TwoI32 { a: 100, b: 101 });
-    assert_eq!(two_i64(), TwoI64 { a: 102, b: 103 });
-    assert_eq!(two_f32(), TwoF32 { a: 104., b: 105. });
-    assert_eq!(two_f64(), TwoF64 { a: 106., b: 107. });
-    assert_eq!(
-        mishmash(),
-        Mishmash { a: 108., b: 109., c: 110, d: 111, e: TwoI32 { a: 112, b: 113 } }
-    );
-}
diff --git a/tests/run-make/wasm-abi/host.wat b/tests/run-make/wasm-abi/host.wat
deleted file mode 100644
index e87097ac8a1..00000000000
--- a/tests/run-make/wasm-abi/host.wat
+++ /dev/null
@@ -1,22 +0,0 @@
-(module
-  (func (export "two_i32") (result i32 i32)
-      i32.const 100
-      i32.const 101)
-  (func (export "two_i64") (result i64 i64)
-      i64.const 102
-      i64.const 103)
-  (func (export "two_f32") (result f32 f32)
-      f32.const 104
-      f32.const 105)
-  (func (export "two_f64") (result f64 f64)
-      f64.const 106
-      f64.const 107)
-
-  (func (export "mishmash") (result f64 f32 i32 i64 i32 i32)
-      f64.const 108
-      f32.const 109
-      i32.const 110
-      i64.const 111
-      i32.const 112
-      i32.const 113)
-)
diff --git a/tests/run-make/wasm-abi/rmake.rs b/tests/run-make/wasm-abi/rmake.rs
deleted file mode 100644
index ff12bcd536e..00000000000
--- a/tests/run-make/wasm-abi/rmake.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-//@ only-wasm32-wasip1
-//@ needs-wasmtime
-
-use run_make_support::{cmd, rustc};
-use std::path::Path;
-
-fn main() {
-    rustc().input("foo.rs").target("wasm32-wasip1").run();
-
-    let file = Path::new("foo.wasm");
-
-    run(&file, "return_two_i32", "1\n2\n");
-    run(&file, "return_two_i64", "3\n4\n");
-    run(&file, "return_two_f32", "5\n6\n");
-    run(&file, "return_two_f64", "7\n8\n");
-    run(&file, "return_mishmash", "9\n10\n11\n12\n13\n14\n");
-    run(&file, "call_imports", "");
-}
-
-fn run(file: &Path, method: &str, expected_output: &str) {
-    cmd("wasmtime")
-        .arg("run")
-        .arg("--preload=host=host.wat")
-        .arg("--invoke")
-        .arg(method)
-        .arg(file)
-        .run()
-        .assert_stdout_equals(expected_output);
-}
diff --git a/tests/rustdoc-json/impl-trait-precise-capturing.rs b/tests/rustdoc-json/impl-trait-precise-capturing.rs
new file mode 100644
index 00000000000..bf98868d145
--- /dev/null
+++ b/tests/rustdoc-json/impl-trait-precise-capturing.rs
@@ -0,0 +1,6 @@
+#![feature(precise_capturing)]
+
+// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\"
+// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\"
+// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\"
+pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout
index e288f8dfce6..9eb8b391e78 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout
@@ -9,9 +9,14 @@ error: expected item, found `;`
   --> $DIR/failed-doctest-extra-semicolon-on-item.rs:12:12
    |
 LL | struct S {}; // unexpected semicolon after struct def
-   |            ^ help: remove this semicolon
+   |            ^
    |
    = help: braced struct declarations are not followed by a semicolon
+help: remove this semicolon
+   |
+LL - struct S {}; // unexpected semicolon after struct def
+LL + struct S {} // unexpected semicolon after struct def
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/rustdoc/issue-102154.rs b/tests/rustdoc-ui/ice-assoc-type-loop-102154.rs
index b36f270806f..68e22ce6ea1 100644
--- a/tests/rustdoc/issue-102154.rs
+++ b/tests/rustdoc-ui/ice-assoc-type-loop-102154.rs
@@ -1,3 +1,6 @@
+//@ check-pass
+// https://github.com/rust-lang/rust/issues/102154
+
 trait A<Y, N> {
     type B;
 }
diff --git a/tests/rustdoc/issue-100620.rs b/tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs
index 097666eb515..e12b214410b 100644
--- a/tests/rustdoc/issue-100620.rs
+++ b/tests/rustdoc-ui/ice-method-where-clause-circular-100620.rs
@@ -1,3 +1,6 @@
+//@ check-pass
+// https://github.com/rust-lang/rust/issues/100620
+
 pub trait Bar<S> {}
 
 pub trait Qux<T> {}
diff --git a/tests/rustdoc/issue-100241.rs b/tests/rustdoc-ui/ice-unresolved-import-100241.rs
index e4c613dd279..eef4b8355bf 100644
--- a/tests/rustdoc/issue-100241.rs
+++ b/tests/rustdoc-ui/ice-unresolved-import-100241.rs
@@ -3,6 +3,8 @@
 // Check that this isn't an ICE
 //@ should-fail
 
+// https://github.com/rust-lang/rust/issues/100241
+
 mod foo {
     pub use inner::S;
     //~^ ERROR unresolved imports `inner`, `foo::S`
diff --git a/tests/rustdoc/issue-108281.rs b/tests/rustdoc/attributes-inlining-108281.rs
index ba6c570b59b..ba6c570b59b 100644
--- a/tests/rustdoc/issue-108281.rs
+++ b/tests/rustdoc/attributes-inlining-108281.rs
diff --git a/tests/rustdoc/issue-101743-bold-tag.rs b/tests/rustdoc/bold-tag-101743.rs
index a81767eeeeb..a81767eeeeb 100644
--- a/tests/rustdoc/issue-101743-bold-tag.rs
+++ b/tests/rustdoc/bold-tag-101743.rs
diff --git a/tests/rustdoc/issue-106421-not-internal.rs b/tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs
index f328a1036eb..a85cfa78cdc 100644
--- a/tests/rustdoc/issue-106421-not-internal.rs
+++ b/tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs
@@ -2,7 +2,10 @@
 //@ ignore-cross-compile
 // This is the version where a non-compiler-internal crate inlines a compiler-internal one.
 // In this case, the item shouldn't be documented, because regular users can't get at it.
+// https://github.com/rust-lang/rust/issues/106421
+#![crate_name="bar"]
+
 extern crate foo;
 
-//@ !has issue_106421_not_internal/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise'
+//@ !has bar/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise'
 pub use foo::FatalError;
diff --git a/tests/rustdoc/issue-106421.rs b/tests/rustdoc/force-unstable-if-unmarked-106421.rs
index c2064c71090..aa88a569aef 100644
--- a/tests/rustdoc/issue-106421.rs
+++ b/tests/rustdoc/force-unstable-if-unmarked-106421.rs
@@ -1,8 +1,10 @@
 //@ aux-build:issue-106421-force-unstable.rs
 //@ ignore-cross-compile
 //@ compile-flags: -Zforce-unstable-if-unmarked
+// https://github.com/rust-lang/rust/issues/106421
+#![crate_name="bar"]
 
 extern crate foo;
 
-//@ has issue_106421/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise'
+//@ has bar/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise'
 pub use foo::FatalError;
diff --git a/tests/rustdoc/issue-105952.rs b/tests/rustdoc/ice-associated-const-equality-105952.rs
index 173efb82f4b..1bcdfac7342 100644
--- a/tests/rustdoc/issue-105952.rs
+++ b/tests/rustdoc/ice-associated-const-equality-105952.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/105952
 #![crate_name = "foo"]
 
 #![feature(associated_const_equality)]
diff --git a/tests/rustdoc/issue-107995.rs b/tests/rustdoc/ice-intra-doc-links-107995.rs
index 57669909aa1..57669909aa1 100644
--- a/tests/rustdoc/issue-107995.rs
+++ b/tests/rustdoc/ice-intra-doc-links-107995.rs
diff --git a/tests/rustdoc/impl-trait-precise-capturing.rs b/tests/rustdoc/impl-trait-precise-capturing.rs
new file mode 100644
index 00000000000..d1987a555c1
--- /dev/null
+++ b/tests/rustdoc/impl-trait-precise-capturing.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+#![feature(precise_capturing)]
+
+//@ has foo/fn.two.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'b, 'a>"
+pub fn two<'a, 'b, 'c>() -> impl Sized + use<'b, 'a /* no 'c */> {}
+
+//@ has foo/fn.params.html '//section[@id="main-content"]//pre' "-> impl Sized + use<'a, T, N>"
+pub fn params<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}
+
+//@ has foo/fn.none.html '//section[@id="main-content"]//pre' "-> impl Sized + use<>"
+pub fn none() -> impl Sized + use<> {}
+
+//@ has foo/fn.first.html '//section[@id="main-content"]//pre' "-> impl use<> + Sized"
+pub fn first() -> impl use<> + Sized {}
diff --git a/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs b/tests/rustdoc/inline-impl-through-glob-import-100204.rs
index 7f05e57ec09..ba6ed427871 100644
--- a/tests/rustdoc/issue-100204-inline-impl-through-glob-import.rs
+++ b/tests/rustdoc/inline-impl-through-glob-import-100204.rs
@@ -2,6 +2,7 @@
 //@ build-aux-docs
 //@ ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/100204
 #![crate_name="second"]
 
 extern crate first;
diff --git a/tests/rustdoc/issue-106142.rs b/tests/rustdoc/issue-106142.rs
deleted file mode 100644
index 52adc5dbbf1..00000000000
--- a/tests/rustdoc/issue-106142.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ has 'issue_106142/a/index.html'
-//@ count 'issue_106142/a/index.html' '//ul[@class="item-table"]//li//a' 1
-
-#![allow(rustdoc::broken_intra_doc_links)]
-
-pub mod a {
-    /// [`m`]
-    pub fn f() {}
-
-    #[macro_export]
-    macro_rules! m {
-        () => {};
-    }
-}
diff --git a/tests/rustdoc/issue-108231.rs b/tests/rustdoc/macro-export-crate-root-108231.rs
index 0d3ad1b0571..0d3ad1b0571 100644
--- a/tests/rustdoc/issue-108231.rs
+++ b/tests/rustdoc/macro-export-crate-root-108231.rs
diff --git a/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs b/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs
new file mode 100644
index 00000000000..0d146a3c5cd
--- /dev/null
+++ b/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs
@@ -0,0 +1,17 @@
+// https://github.com/rust-lang/rust/issues/106142
+#![crate_name="foo"]
+
+//@ has 'foo/a/index.html'
+//@ count 'foo/a/index.html' '//ul[@class="item-table"]//li//a' 1
+
+#![allow(rustdoc::broken_intra_doc_links)]
+
+pub mod a {
+    /// [`m`]
+    pub fn f() {}
+
+    #[macro_export]
+    macro_rules! m {
+        () => {};
+    }
+}
diff --git a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/tests/rustdoc/multiple-foreigns-w-same-name-99734.rs
index d7c4f1db320..60a2aa388ee 100644
--- a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs
+++ b/tests/rustdoc/multiple-foreigns-w-same-name-99734.rs
@@ -2,6 +2,7 @@
 //@ build-aux-docs
 //@ ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/99734
 #![crate_name = "foo"]
 
 #[macro_use]
diff --git a/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs b/tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs
index e7fb4fb3f0e..4a1798a8496 100644
--- a/tests/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs
+++ b/tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs
@@ -2,6 +2,7 @@
 //@ build-aux-docs
 //@ ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/99221
 #![crate_name = "foo"]
 
 #[macro_use]
diff --git a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/tests/rustdoc/multiple-mods-w-same-name-99734.rs
index 627cfc0b80b..d48464c478f 100644
--- a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs
+++ b/tests/rustdoc/multiple-mods-w-same-name-99734.rs
@@ -2,6 +2,7 @@
 //@ build-aux-docs
 //@ ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/99734
 #![crate_name = "foo"]
 
 #[macro_use]
diff --git a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs b/tests/rustdoc/multiple-structs-w-same-name-99221.rs
index 8758342fe07..4c2f77fec23 100644
--- a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs
+++ b/tests/rustdoc/multiple-structs-w-same-name-99221.rs
@@ -2,6 +2,7 @@
 //@ build-aux-docs
 //@ ignore-cross-compile
 
+// https://github.com/rust-lang/rust/issues/99221
 #![crate_name = "foo"]
 
 #[macro_use]
diff --git a/tests/rustdoc/issue-105735-overlapping-reexport-2.rs b/tests/rustdoc/overlapping-reexport-105735-2.rs
index 946184c5a04..9f823ec5923 100644
--- a/tests/rustdoc/issue-105735-overlapping-reexport-2.rs
+++ b/tests/rustdoc/overlapping-reexport-105735-2.rs
@@ -1,4 +1,5 @@
 // Regression test to ensure that both `AtomicU8` items are displayed but not the re-export.
+// https://github.com/rust-lang/rust/issues/105735
 
 #![crate_name = "foo"]
 #![no_std]
diff --git a/tests/rustdoc/issue-105735-overlapping-reexport.rs b/tests/rustdoc/overlapping-reexport-105735.rs
index 0fd17fd9577..2a2d0fa9830 100644
--- a/tests/rustdoc/issue-105735-overlapping-reexport.rs
+++ b/tests/rustdoc/overlapping-reexport-105735.rs
@@ -1,4 +1,5 @@
 // Regression test to ensure that both `AtomicU8` items are displayed but not the re-export.
+// https://github.com/rust-lang/rust/issues/105735
 
 #![crate_name = "foo"]
 #![no_std]
diff --git a/tests/rustdoc/issue-107350.rs b/tests/rustdoc/pub-use-loop-107350.rs
index 4ec9133e2d2..4ec9133e2d2 100644
--- a/tests/rustdoc/issue-107350.rs
+++ b/tests/rustdoc/pub-use-loop-107350.rs
diff --git a/tests/rustdoc/issue-108679-reexport-of-reexport.rs b/tests/rustdoc/reexport-of-reexport-108679.rs
index 5c1b4bcbd83..5c1b4bcbd83 100644
--- a/tests/rustdoc/issue-108679-reexport-of-reexport.rs
+++ b/tests/rustdoc/reexport-of-reexport-108679.rs
diff --git a/tests/ui/abi/numbers-arithmetic/return-float.rs b/tests/ui/abi/numbers-arithmetic/return-float.rs
new file mode 100644
index 00000000000..66a6d66911d
--- /dev/null
+++ b/tests/ui/abi/numbers-arithmetic/return-float.rs
@@ -0,0 +1,61 @@
+//@ run-pass
+//@ compile-flags: -Copt-level=0
+
+// Test that floats (in particular signalling NaNs) are losslessly returned from functions.
+
+fn main() {
+    // FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled on
+    // x86.
+    if cfg!(not(all(target_arch = "x86", not(target_feature = "sse2")))) {
+        let bits_f32 = std::hint::black_box([
+            4.2_f32.to_bits(),
+            f32::INFINITY.to_bits(),
+            f32::NEG_INFINITY.to_bits(),
+            f32::NAN.to_bits(),
+            // These two masks cover all the mantissa bits. One of them is a signalling NaN, the
+            // other is quiet.
+            // Similar to the masks in `test_float_bits_conv` in library/std/src/f32/tests.rs
+            f32::NAN.to_bits() ^ 0x002A_AAAA,
+            f32::NAN.to_bits() ^ 0x0055_5555,
+            // Same as above but with the sign bit flipped.
+            f32::NAN.to_bits() ^ 0x802A_AAAA,
+            f32::NAN.to_bits() ^ 0x8055_5555,
+        ]);
+        for bits in bits_f32 {
+            assert_eq!(identity(f32::from_bits(bits)).to_bits(), bits);
+            // Test types that are returned as scalar pairs.
+            assert_eq!(identity((f32::from_bits(bits), 42)).0.to_bits(), bits);
+            assert_eq!(identity((42, f32::from_bits(bits))).1.to_bits(), bits);
+            let (a, b) = identity((f32::from_bits(bits), f32::from_bits(bits)));
+            assert_eq!((a.to_bits(), b.to_bits()), (bits, bits));
+        }
+
+        let bits_f64 = std::hint::black_box([
+            4.2_f64.to_bits(),
+            f64::INFINITY.to_bits(),
+            f64::NEG_INFINITY.to_bits(),
+            f64::NAN.to_bits(),
+            // These two masks cover all the mantissa bits. One of them is a signalling NaN, the
+            // other is quiet.
+            // Similar to the masks in `test_float_bits_conv` in library/std/src/f64/tests.rs
+            f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA,
+            f64::NAN.to_bits() ^ 0x0005_5555_5555_5555,
+            // Same as above but with the sign bit flipped.
+            f64::NAN.to_bits() ^ 0x800A_AAAA_AAAA_AAAA,
+            f64::NAN.to_bits() ^ 0x8005_5555_5555_5555,
+        ]);
+        for bits in bits_f64 {
+            assert_eq!(identity(f64::from_bits(bits)).to_bits(), bits);
+            // Test types that are returned as scalar pairs.
+            assert_eq!(identity((f64::from_bits(bits), 42)).0.to_bits(), bits);
+            assert_eq!(identity((42, f64::from_bits(bits))).1.to_bits(), bits);
+            let (a, b) = identity((f64::from_bits(bits), f64::from_bits(bits)));
+            assert_eq!((a.to_bits(), b.to_bits()), (bits, bits));
+        }
+    }
+}
+
+#[inline(never)]
+fn identity<T>(x: T) -> T {
+    x
+}
diff --git a/tests/ui/abi/removed-wasm-abi.rs b/tests/ui/abi/removed-wasm-abi.rs
new file mode 100644
index 00000000000..a45e42bfe02
--- /dev/null
+++ b/tests/ui/abi/removed-wasm-abi.rs
@@ -0,0 +1,4 @@
+extern "wasm" fn test() {}
+//~^ ERROR invalid ABI: found `wasm`
+
+fn main() {}
diff --git a/tests/ui/abi/removed-wasm-abi.stderr b/tests/ui/abi/removed-wasm-abi.stderr
new file mode 100644
index 00000000000..6007c4e2580
--- /dev/null
+++ b/tests/ui/abi/removed-wasm-abi.stderr
@@ -0,0 +1,12 @@
+error[E0703]: invalid ABI: found `wasm`
+  --> $DIR/removed-wasm-abi.rs:1:8
+   |
+LL | extern "wasm" fn test() {}
+   |        ^^^^^^ invalid ABI
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+   = note: non-standard wasm ABI is no longer supported
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0703`.
diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr
index 72a9519e3e7..123e7663257 100644
--- a/tests/ui/abi/unsupported.aarch64.stderr
+++ b/tests/ui/abi/unsupported.aarch64.stderr
@@ -1,53 +1,47 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
-   |
-LL | extern "wasm" fn wasm() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:33:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:41:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+  --> $DIR/unsupported.rs:40:1
    |
 LL | extern "riscv-interrupt-m" fn riscv() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
+  --> $DIR/unsupported.rs:45:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:53:1
+  --> $DIR/unsupported.rs:50:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:59:1
+  --> $DIR/unsupported.rs:56:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -56,6 +50,6 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error: aborting due to 8 previous errors; 1 warning emitted
+error: aborting due to 7 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr
index 473b59a334d..7376bb17d6b 100644
--- a/tests/ui/abi/unsupported.arm.stderr
+++ b/tests/ui/abi/unsupported.arm.stderr
@@ -1,47 +1,41 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
-   |
-LL | extern "wasm" fn wasm() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:41:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+  --> $DIR/unsupported.rs:40:1
    |
 LL | extern "riscv-interrupt-m" fn riscv() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
+  --> $DIR/unsupported.rs:45:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:53:1
+  --> $DIR/unsupported.rs:50:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:59:1
+  --> $DIR/unsupported.rs:56:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error: aborting due to 7 previous errors; 1 warning emitted
+error: aborting due to 6 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr
index f0af3d251e2..23b0e581887 100644
--- a/tests/ui/abi/unsupported.i686.stderr
+++ b/tests/ui/abi/unsupported.i686.stderr
@@ -1,39 +1,33 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
-   |
-LL | extern "wasm" fn wasm() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:33:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:41:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+  --> $DIR/unsupported.rs:40:1
    |
 LL | extern "riscv-interrupt-m" fn riscv() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr
index b466a2a6ff8..708fd2c92a9 100644
--- a/tests/ui/abi/unsupported.riscv32.stderr
+++ b/tests/ui/abi/unsupported.riscv32.stderr
@@ -1,47 +1,41 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
-   |
-LL | extern "wasm" fn wasm() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:33:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:41:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
+  --> $DIR/unsupported.rs:45:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:53:1
+  --> $DIR/unsupported.rs:50:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:59:1
+  --> $DIR/unsupported.rs:56:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error: aborting due to 7 previous errors; 1 warning emitted
+error: aborting due to 6 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr
index b466a2a6ff8..708fd2c92a9 100644
--- a/tests/ui/abi/unsupported.riscv64.stderr
+++ b/tests/ui/abi/unsupported.riscv64.stderr
@@ -1,47 +1,41 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
-   |
-LL | extern "wasm" fn wasm() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:33:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:41:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
+  --> $DIR/unsupported.rs:45:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:53:1
+  --> $DIR/unsupported.rs:50:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:59:1
+  --> $DIR/unsupported.rs:56:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error: aborting due to 7 previous errors; 1 warning emitted
+error: aborting due to 6 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs
index cd7e76c7158..c12883e3fce 100644
--- a/tests/ui/abi/unsupported.rs
+++ b/tests/ui/abi/unsupported.rs
@@ -19,7 +19,6 @@
     abi_ptx,
     abi_msp430_interrupt,
     abi_avr_interrupt,
-    wasm_abi,
     abi_x86_interrupt,
     abi_riscv_interrupt
 )]
@@ -28,8 +27,6 @@ trait Sized {}
 
 extern "ptx-kernel" fn ptx() {}
 //~^ ERROR is not a supported ABI
-extern "wasm" fn wasm() {}
-//~^ ERROR is not a supported ABI
 extern "aapcs" fn aapcs() {}
 //[x64]~^ ERROR is not a supported ABI
 //[i686]~^^ ERROR is not a supported ABI
diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr
index 4a2b7e74969..7b918a948d3 100644
--- a/tests/ui/abi/unsupported.x64.stderr
+++ b/tests/ui/abi/unsupported.x64.stderr
@@ -1,47 +1,41 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
-   |
-LL | extern "wasm" fn wasm() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:33:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:41:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+  --> $DIR/unsupported.rs:40:1
    |
 LL | extern "riscv-interrupt-m" fn riscv() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:53:1
+  --> $DIR/unsupported.rs:50:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:59:1
+  --> $DIR/unsupported.rs:56:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,6 +44,6 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error: aborting due to 7 previous errors; 1 warning emitted
+error: aborting due to 6 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr
index 539c134472f..d21a8ab1f85 100644
--- a/tests/ui/asm/aarch64/parse-error.stderr
+++ b/tests/ui/asm/aarch64/parse-error.stderr
@@ -313,74 +313,90 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:39:37
    |
-LL |     let mut foo = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         asm!("{}", options(), const foo);
    |                                     ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:47:44
    |
-LL |     let mut foo = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         asm!("{}", clobber_abi("C"), const foo);
    |                                            ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:50:55
    |
-LL |     let mut foo = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         asm!("{}", options(), clobber_abi("C"), const foo);
    |                                                       ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:52:31
    |
-LL |     let mut foo = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                               ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:52:46
    |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                              ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:59:45
    |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
 LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                                             ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:61:45
    |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
 LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                                             ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:63:41
    |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
 LL |         asm!("{1}", in("x0") foo, const bar);
    |                                         ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error: aborting due to 57 previous errors
 
diff --git a/tests/ui/asm/binary_asm_labels.rs b/tests/ui/asm/binary_asm_labels.rs
new file mode 100644
index 00000000000..3f545880254
--- /dev/null
+++ b/tests/ui/asm/binary_asm_labels.rs
@@ -0,0 +1,17 @@
+//@ needs-asm-support
+//@ only-x86_64
+
+// tests that labels containing only the digits 0 and 1 are rejected
+// uses of such labels can sometimes be interpreted as a binary literal
+
+use std::arch::{asm, global_asm};
+
+fn main() {
+    unsafe {
+        asm!("0: jmp 0b"); //~ ERROR avoid using labels containing only the digits
+        asm!("1: jmp 1b"); //~ ERROR avoid using labels containing only the digits
+        asm!("10: jmp 10b"); //~ ERROR avoid using labels containing only the digits
+        asm!("01: jmp 01b"); //~ ERROR avoid using labels containing only the digits
+        asm!("1001101: jmp 1001101b"); //~ ERROR avoid using labels containing only the digits
+    }
+}
diff --git a/tests/ui/asm/binary_asm_labels.stderr b/tests/ui/asm/binary_asm_labels.stderr
new file mode 100644
index 00000000000..1f2943084f1
--- /dev/null
+++ b/tests/ui/asm/binary_asm_labels.stderr
@@ -0,0 +1,43 @@
+error: avoid using labels containing only the digits `0` and `1` in inline assembly
+  --> $DIR/binary_asm_labels.rs:11:15
+   |
+LL |         asm!("0: jmp 0b");
+   |               ^ use a different label that doesn't start with `0` or `1`
+   |
+   = note: an LLVM bug makes these labels ambiguous with a binary literal number
+   = note: `#[deny(binary_asm_labels)]` on by default
+
+error: avoid using labels containing only the digits `0` and `1` in inline assembly
+  --> $DIR/binary_asm_labels.rs:12:15
+   |
+LL |         asm!("1: jmp 1b");
+   |               ^ use a different label that doesn't start with `0` or `1`
+   |
+   = note: an LLVM bug makes these labels ambiguous with a binary literal number
+
+error: avoid using labels containing only the digits `0` and `1` in inline assembly
+  --> $DIR/binary_asm_labels.rs:13:15
+   |
+LL |         asm!("10: jmp 10b");
+   |               ^^ use a different label that doesn't start with `0` or `1`
+   |
+   = note: an LLVM bug makes these labels ambiguous with a binary literal number
+
+error: avoid using labels containing only the digits `0` and `1` in inline assembly
+  --> $DIR/binary_asm_labels.rs:14:15
+   |
+LL |         asm!("01: jmp 01b");
+   |               ^^ use a different label that doesn't start with `0` or `1`
+   |
+   = note: an LLVM bug makes these labels ambiguous with a binary literal number
+
+error: avoid using labels containing only the digits `0` and `1` in inline assembly
+  --> $DIR/binary_asm_labels.rs:15:15
+   |
+LL |         asm!("1001101: jmp 1001101b");
+   |               ^^^^^^^ use a different label that doesn't start with `0` or `1`
+   |
+   = note: an LLVM bug makes these labels ambiguous with a binary literal number
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs
index 96ccdef75b0..d2ca6fe8808 100644
--- a/tests/ui/asm/named-asm-labels.rs
+++ b/tests/ui/asm/named-asm-labels.rs
@@ -28,11 +28,13 @@ fn main() {
         // Multiple labels on one line
         asm!("foo: bar1: nop");
         //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
 
         // Multiple lines
         asm!("foo1: nop", "nop"); //~ ERROR avoid using named labels
         asm!("foo2: foo3: nop", "nop");
         //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
         asm!("nop", "foo4: nop"); //~ ERROR avoid using named labels
         asm!("foo5: nop", "foo6: nop");
         //~^ ERROR avoid using named labels
@@ -41,16 +43,19 @@ fn main() {
         // Statement separator
         asm!("foo7: nop; foo8: nop");
         //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
         asm!("foo9: nop; nop"); //~ ERROR avoid using named labels
         asm!("nop; foo10: nop"); //~ ERROR avoid using named labels
 
         // Escaped newline
         asm!("bar2: nop\n bar3: nop");
         //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
         asm!("bar4: nop\n nop"); //~ ERROR avoid using named labels
         asm!("nop\n bar5: nop"); //~ ERROR avoid using named labels
         asm!("nop\n bar6: bar7: nop");
         //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
 
         // Raw strings
         asm!(
@@ -60,6 +65,7 @@ fn main() {
             "
         );
         //~^^^^ ERROR avoid using named labels
+        //~^^^^ ERROR avoid using named labels
 
         asm!(
             r###"
@@ -81,9 +87,15 @@ fn main() {
         asm!("blah1: 2bar: nop"); //~ ERROR avoid using named labels
 
         // Duplicate labels
-        asm!("def: def: nop"); //~ ERROR avoid using named labels
-        asm!("def: nop\ndef: nop"); //~ ERROR avoid using named labels
-        asm!("def: nop; def: nop"); //~ ERROR avoid using named labels
+        asm!("def: def: nop");
+        //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
+        asm!("def: nop\ndef: nop");
+        //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
+        asm!("def: nop; def: nop");
+        //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
 
         // Trying to break parsing
         asm!(":");
@@ -141,7 +153,11 @@ fn main() {
         asm!("{1}: nop", "/* {0} */", const 10, const 20); //~ ERROR avoid using named labels
 
         // Test include_str in asm
-        asm!(include_str!("named-asm-labels.s")); //~ ERROR avoid using named labels
+        asm!(include_str!("named-asm-labels.s"));
+        //~^ ERROR avoid using named labels
+        //~^^ ERROR avoid using named labels
+        //~^^^ ERROR avoid using named labels
+        //~^^^^ ERROR avoid using named labels
 
         // Test allowing or warning on the lint instead
         #[allow(named_asm_labels)]
diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr
index 36fd6983951..20b7d64f9e7 100644
--- a/tests/ui/asm/named-asm-labels.stderr
+++ b/tests/ui/asm/named-asm-labels.stderr
@@ -21,13 +21,22 @@ error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:29:15
    |
 LL |         asm!("foo: bar1: nop");
-   |               ^^^  ^^^^
+   |               ^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:33:15
+  --> $DIR/named-asm-labels.rs:29:20
+   |
+LL |         asm!("foo: bar1: nop");
+   |                    ^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:34:15
    |
 LL |         asm!("foo1: nop", "nop");
    |               ^^^^
@@ -36,16 +45,25 @@ LL |         asm!("foo1: nop", "nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:34:15
+  --> $DIR/named-asm-labels.rs:35:15
    |
 LL |         asm!("foo2: foo3: nop", "nop");
-   |               ^^^^  ^^^^
+   |               ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:36:22
+  --> $DIR/named-asm-labels.rs:35:21
+   |
+LL |         asm!("foo2: foo3: nop", "nop");
+   |                     ^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:38:22
    |
 LL |         asm!("nop", "foo4: nop");
    |                      ^^^^
@@ -54,7 +72,7 @@ LL |         asm!("nop", "foo4: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:37:15
+  --> $DIR/named-asm-labels.rs:39:15
    |
 LL |         asm!("foo5: nop", "foo6: nop");
    |               ^^^^
@@ -63,7 +81,7 @@ LL |         asm!("foo5: nop", "foo6: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:37:28
+  --> $DIR/named-asm-labels.rs:39:28
    |
 LL |         asm!("foo5: nop", "foo6: nop");
    |                            ^^^^
@@ -72,16 +90,25 @@ LL |         asm!("foo5: nop", "foo6: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:42:15
+  --> $DIR/named-asm-labels.rs:44:15
    |
 LL |         asm!("foo7: nop; foo8: nop");
-   |               ^^^^       ^^^^
+   |               ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:44:15
+  --> $DIR/named-asm-labels.rs:44:26
+   |
+LL |         asm!("foo7: nop; foo8: nop");
+   |                          ^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:47:15
    |
 LL |         asm!("foo9: nop; nop");
    |               ^^^^
@@ -90,7 +117,7 @@ LL |         asm!("foo9: nop; nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:45:20
+  --> $DIR/named-asm-labels.rs:48:20
    |
 LL |         asm!("nop; foo10: nop");
    |                    ^^^^^
@@ -99,16 +126,25 @@ LL |         asm!("nop; foo10: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:48:15
+  --> $DIR/named-asm-labels.rs:51:15
    |
 LL |         asm!("bar2: nop\n bar3: nop");
-   |               ^^^^        ^^^^
+   |               ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:50:15
+  --> $DIR/named-asm-labels.rs:51:27
+   |
+LL |         asm!("bar2: nop\n bar3: nop");
+   |                           ^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:54:15
    |
 LL |         asm!("bar4: nop\n nop");
    |               ^^^^
@@ -117,7 +153,7 @@ LL |         asm!("bar4: nop\n nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:51:21
+  --> $DIR/named-asm-labels.rs:55:21
    |
 LL |         asm!("nop\n bar5: nop");
    |                     ^^^^
@@ -126,19 +162,35 @@ LL |         asm!("nop\n bar5: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:52:21
+  --> $DIR/named-asm-labels.rs:56:21
    |
 LL |         asm!("nop\n bar6: bar7: nop");
-   |                     ^^^^  ^^^^
+   |                     ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:58:13
+  --> $DIR/named-asm-labels.rs:56:27
+   |
+LL |         asm!("nop\n bar6: bar7: nop");
+   |                           ^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:63:13
    |
 LL |             blah2: nop
    |             ^^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:64:13
+   |
 LL |             blah3: nop
    |             ^^^^^
    |
@@ -146,7 +198,7 @@ LL |             blah3: nop
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:67:19
+  --> $DIR/named-asm-labels.rs:73:19
    |
 LL |             nop ; blah4: nop
    |                   ^^^^^
@@ -155,7 +207,7 @@ LL |             nop ; blah4: nop
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:81:15
+  --> $DIR/named-asm-labels.rs:87:15
    |
 LL |         asm!("blah1: 2bar: nop");
    |               ^^^^^
@@ -164,7 +216,7 @@ LL |         asm!("blah1: 2bar: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:84:15
+  --> $DIR/named-asm-labels.rs:90:15
    |
 LL |         asm!("def: def: nop");
    |               ^^^
@@ -173,7 +225,17 @@ LL |         asm!("def: def: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:85:15
+  --> $DIR/named-asm-labels.rs:90:15
+   |
+LL |         asm!("def: def: nop");
+   |               ^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:93:15
    |
 LL |         asm!("def: nop\ndef: nop");
    |               ^^^
@@ -182,16 +244,36 @@ LL |         asm!("def: nop\ndef: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:86:15
+  --> $DIR/named-asm-labels.rs:93:15
+   |
+LL |         asm!("def: nop\ndef: nop");
+   |               ^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:96:15
+   |
+LL |         asm!("def: nop; def: nop");
+   |               ^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:96:15
    |
 LL |         asm!("def: nop; def: nop");
    |               ^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:94:15
+  --> $DIR/named-asm-labels.rs:106:15
    |
 LL |         asm!("fooo\u{003A} nop");
    |               ^^^^^^^^^^^^^^^^
@@ -200,7 +282,7 @@ LL |         asm!("fooo\u{003A} nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:95:15
+  --> $DIR/named-asm-labels.rs:107:15
    |
 LL |         asm!("foooo\x3A nop");
    |               ^^^^^^^^^^^^^
@@ -209,7 +291,7 @@ LL |         asm!("foooo\x3A nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:98:15
+  --> $DIR/named-asm-labels.rs:110:15
    |
 LL |         asm!("fooooo:\u{000A} nop");
    |               ^^^^^^
@@ -218,7 +300,7 @@ LL |         asm!("fooooo:\u{000A} nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:99:15
+  --> $DIR/named-asm-labels.rs:111:15
    |
 LL |         asm!("foooooo:\x0A nop");
    |               ^^^^^^^
@@ -227,16 +309,17 @@ LL |         asm!("foooooo:\x0A nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:103:14
+  --> $DIR/named-asm-labels.rs:115:14
    |
 LL |         asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70");
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+   = note: the label may be declared in the expansion of a macro
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:111:13
+  --> $DIR/named-asm-labels.rs:123:13
    |
 LL |             ab: nop // ab: does foo
    |             ^^
@@ -245,97 +328,140 @@ LL |             ab: nop // ab: does foo
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:131:19
+  --> $DIR/named-asm-labels.rs:143:19
    |
 LL |             asm!("test_{}: nop", in(reg) 10);
    |                   ^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:133:15
+  --> $DIR/named-asm-labels.rs:145:15
    |
 LL |         asm!("test_{}: nop", const 10);
    |               ^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:134:15
+  --> $DIR/named-asm-labels.rs:146:15
    |
 LL |         asm!("test_{}: nop", sym main);
    |               ^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:135:15
+  --> $DIR/named-asm-labels.rs:147:15
    |
 LL |         asm!("{}_test: nop", const 10);
    |               ^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:136:15
+  --> $DIR/named-asm-labels.rs:148:15
    |
 LL |         asm!("test_{}_test: nop", const 10);
    |               ^^^^^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:137:15
+  --> $DIR/named-asm-labels.rs:149:15
    |
 LL |         asm!("{}: nop", const 10);
    |               ^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:139:15
+  --> $DIR/named-asm-labels.rs:151:15
    |
 LL |         asm!("{uwu}: nop", uwu = const 10);
    |               ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:140:15
+  --> $DIR/named-asm-labels.rs:152:15
    |
 LL |         asm!("{0}: nop", const 10);
    |               ^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:141:15
+  --> $DIR/named-asm-labels.rs:153:15
    |
 LL |         asm!("{1}: nop", "/* {0} */", const 10, const 20);
    |               ^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: format arguments may expand to a non-numeric value
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:156:14
+   |
+LL |         asm!(include_str!("named-asm-labels.s"));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+   = note: the label may be declared in the expansion of a macro
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:156:14
+   |
+LL |         asm!(include_str!("named-asm-labels.s"));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+   = note: the label may be declared in the expansion of a macro
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: avoid using named labels in inline assembly
+  --> $DIR/named-asm-labels.rs:156:14
+   |
+LL |         asm!(include_str!("named-asm-labels.s"));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+   = note: the label may be declared in the expansion of a macro
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:144:14
+  --> $DIR/named-asm-labels.rs:156:14
    |
 LL |         asm!(include_str!("named-asm-labels.s"));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
+   = note: the label may be declared in the expansion of a macro
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:154:19
+  --> $DIR/named-asm-labels.rs:170:19
    |
 LL |             asm!("warned: nop");
    |                   ^^^^^^
@@ -343,13 +469,13 @@ LL |             asm!("warned: nop");
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 note: the lint level is defined here
-  --> $DIR/named-asm-labels.rs:152:16
+  --> $DIR/named-asm-labels.rs:168:16
    |
 LL |         #[warn(named_asm_labels)]
    |                ^^^^^^^^^^^^^^^^
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:163:20
+  --> $DIR/named-asm-labels.rs:179:20
    |
 LL |     unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
    |                    ^^^^^
@@ -358,7 +484,7 @@ LL |     unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noret
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:169:20
+  --> $DIR/named-asm-labels.rs:185:20
    |
 LL |     unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
    |                    ^^^^^
@@ -367,7 +493,7 @@ LL |     unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:177:20
+  --> $DIR/named-asm-labels.rs:193:20
    |
 LL |     unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) }
    |                    ^^^^^
@@ -376,7 +502,7 @@ LL |     unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) }
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:187:24
+  --> $DIR/named-asm-labels.rs:203:24
    |
 LL |         unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) }
    |                        ^^^^^
@@ -385,7 +511,7 @@ LL |         unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) }
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:196:15
+  --> $DIR/named-asm-labels.rs:212:15
    |
 LL |         asm!("closure1: nop");
    |               ^^^^^^^^
@@ -394,7 +520,7 @@ LL |         asm!("closure1: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:200:15
+  --> $DIR/named-asm-labels.rs:216:15
    |
 LL |         asm!("closure2: nop");
    |               ^^^^^^^^
@@ -403,7 +529,7 @@ LL |         asm!("closure2: nop");
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:210:19
+  --> $DIR/named-asm-labels.rs:226:19
    |
 LL |             asm!("closure3: nop");
    |                   ^^^^^^^^
@@ -411,5 +537,5 @@ LL |             asm!("closure3: nop");
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
-error: aborting due to 44 previous errors; 1 warning emitted
+error: aborting due to 56 previous errors; 1 warning emitted
 
diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr
index 80ee5191dbb..1999cd09aa3 100644
--- a/tests/ui/asm/parse-error.stderr
+++ b/tests/ui/asm/parse-error.stderr
@@ -371,47 +371,57 @@ LL | global_asm!("{}", label {});
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:39:37
    |
-LL |     let mut foo = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         asm!("{}", options(), const foo);
    |                                     ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:71:44
    |
-LL |     let mut foo = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         asm!("{}", clobber_abi("C"), const foo);
    |                                            ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:74:55
    |
-LL |     let mut foo = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         asm!("{}", options(), clobber_abi("C"), const foo);
    |                                                       ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:76:31
    |
-LL |     let mut foo = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                               ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:76:46
    |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                              ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error: aborting due to 64 previous errors
 
diff --git a/tests/ui/asm/type-check-1.stderr b/tests/ui/asm/type-check-1.stderr
index 07a609c5213..18526232118 100644
--- a/tests/ui/asm/type-check-1.stderr
+++ b/tests/ui/asm/type-check-1.stderr
@@ -1,29 +1,35 @@
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/type-check-1.rs:41:26
    |
-LL |         let x = 0;
-   |         ----- help: consider using `const` instead of `let`: `const x`
-...
 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 |         let x = 0;
-   |         ----- help: consider using `const` instead of `let`: `const x`
-...
 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 |         let x = 0;
-   |         ----- help: consider using `const` instead of `let`: `const x`
-...
 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
diff --git a/tests/ui/asm/x86_64/x86_64_parse_error.stderr b/tests/ui/asm/x86_64/x86_64_parse_error.stderr
index f2854ae5128..9751f7b09d0 100644
--- a/tests/ui/asm/x86_64/x86_64_parse_error.stderr
+++ b/tests/ui/asm/x86_64/x86_64_parse_error.stderr
@@ -15,29 +15,35 @@ LL |         asm!("{1}", in("eax") foo, const bar);
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/x86_64_parse_error.rs:13:46
    |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
 LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                                              ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/x86_64_parse_error.rs:15:46
    |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
 LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                                              ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/x86_64_parse_error.rs:17:42
    |
-LL |     let mut bar = 0;
-   |     ----------- help: consider using `const` instead of `let`: `const bar`
-...
 LL |         asm!("{1}", in("eax") foo, const bar);
    |                                          ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const bar: /* Type */ = 0;
+   |     ~~~~~    ++++++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
index a98bb0764c0..0ccde7d8709 100644
--- a/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
+++ b/tests/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
@@ -2,115 +2,229 @@ error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:8:13
    |
 LL |     let _ = await bar();
-   |             ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+   |             ^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await bar();
+LL +     let _ = bar().await;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:12:13
    |
 LL |     let _ = await? bar();
-   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
+   |             ^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await? bar();
+LL +     let _ = bar().await?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:16:13
    |
 LL |     let _ = await bar()?;
-   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
+   |             ^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await bar()?;
+LL +     let _ = bar()?.await;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:20:13
    |
 LL |     let _ = await { bar() };
-   |             ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
+   |             ^^^^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await { bar() };
+LL +     let _ = { bar() }.await;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:24:13
    |
 LL |     let _ = await(bar());
-   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`
+   |             ^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await(bar());
+LL +     let _ = (bar()).await;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:28:13
    |
 LL |     let _ = await { bar() }?;
-   |             ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
+   |             ^^^^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await { bar() }?;
+LL +     let _ = { bar() }.await?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:32:14
    |
 LL |     let _ = (await bar())?;
-   |              ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+   |              ^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = (await bar())?;
+LL +     let _ = (bar().await)?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:36:24
    |
 LL |     let _ = bar().await();
-   |                        ^^ help: `await` is not a method call, remove the parentheses
+   |                        ^^
+   |
+help: `await` is not a method call, remove the parentheses
+   |
+LL -     let _ = bar().await();
+LL +     let _ = bar().await;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:40:24
    |
 LL |     let _ = bar().await()?;
-   |                        ^^ help: `await` is not a method call, remove the parentheses
+   |                        ^^
+   |
+help: `await` is not a method call, remove the parentheses
+   |
+LL -     let _ = bar().await()?;
+LL +     let _ = bar().await?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:52:13
    |
 LL |     let _ = await bar();
-   |             ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+   |             ^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await bar();
+LL +     let _ = bar().await;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:56:13
    |
 LL |     let _ = await? bar();
-   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
+   |             ^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await? bar();
+LL +     let _ = bar().await?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:60:13
    |
 LL |     let _ = await bar()?;
-   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
+   |             ^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await bar()?;
+LL +     let _ = bar()?.await;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:64:14
    |
 LL |     let _ = (await bar())?;
-   |              ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+   |              ^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = (await bar())?;
+LL +     let _ = (bar().await)?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:68:24
    |
 LL |     let _ = bar().await();
-   |                        ^^ help: `await` is not a method call, remove the parentheses
+   |                        ^^
+   |
+help: `await` is not a method call, remove the parentheses
+   |
+LL -     let _ = bar().await();
+LL +     let _ = bar().await;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:73:24
    |
 LL |     let _ = bar().await()?;
-   |                        ^^ help: `await` is not a method call, remove the parentheses
+   |                        ^^
+   |
+help: `await` is not a method call, remove the parentheses
+   |
+LL -     let _ = bar().await()?;
+LL +     let _ = bar().await?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:101:13
    |
 LL |     let _ = await!(bar());
-   |             ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+   |             ^^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await!(bar());
+LL +     let _ = bar().await);
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:105:13
    |
 LL |     let _ = await!(bar())?;
-   |             ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+   |             ^^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     let _ = await!(bar())?;
+LL +     let _ = bar().await)?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:110:17
    |
 LL |         let _ = await!(bar())?;
-   |                 ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+   |                 ^^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -         let _ = await!(bar())?;
+LL +         let _ = bar().await)?;
+   |
 
 error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:117:17
    |
 LL |         let _ = await!(bar())?;
-   |                 ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+   |                 ^^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -         let _ = await!(bar())?;
+LL +         let _ = bar().await)?;
+   |
 
 error: expected expression, found `=>`
   --> $DIR/incorrect-syntax-suggestions.rs:124:25
@@ -124,7 +238,13 @@ error: incorrect use of `await`
   --> $DIR/incorrect-syntax-suggestions.rs:124:11
    |
 LL |     match await { await => () }
-   |           ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`
+   |           ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     match await { await => () }
+LL +     match { await => () }.await
+   |
 
 error: expected one of `.`, `?`, `{`, or an operator, found `}`
   --> $DIR/incorrect-syntax-suggestions.rs:127:1
diff --git a/tests/ui/attributes/issue-90873.stderr b/tests/ui/attributes/issue-90873.stderr
index 5a8bbaf8ec1..444497538e8 100644
--- a/tests/ui/attributes/issue-90873.stderr
+++ b/tests/ui/attributes/issue-90873.stderr
@@ -32,7 +32,12 @@ error: missing type for `static` item
   --> $DIR/issue-90873.rs:1:17
    |
 LL | #![u=||{static d=||1;}]
-   |                 ^ help: provide a type for the item: `: <type>`
+   |                 ^
+   |
+help: provide a type for the item
+   |
+LL | #![u=||{static d: <type>=||1;}]
+   |                 ++++++++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/backtrace/synchronized-panic-handler.rs b/tests/ui/backtrace/synchronized-panic-handler.rs
new file mode 100644
index 00000000000..00eb249da1d
--- /dev/null
+++ b/tests/ui/backtrace/synchronized-panic-handler.rs
@@ -0,0 +1,17 @@
+//@ run-pass
+//@ check-run-results
+//@ edition:2021
+//@ exec-env:RUST_BACKTRACE=0
+//@ needs-threads
+use std::thread;
+const PANIC_MESSAGE: &str = "oops oh no woe is me";
+
+fn entry() {
+    panic!("{PANIC_MESSAGE}")
+}
+
+fn main() {
+    let (a, b) = (thread::spawn(entry), thread::spawn(entry));
+    assert_eq!(&**a.join().unwrap_err().downcast::<String>().unwrap(), PANIC_MESSAGE);
+    assert_eq!(&**b.join().unwrap_err().downcast::<String>().unwrap(), PANIC_MESSAGE);
+}
diff --git a/tests/ui/backtrace/synchronized-panic-handler.run.stderr b/tests/ui/backtrace/synchronized-panic-handler.run.stderr
new file mode 100644
index 00000000000..b7c815a94c8
--- /dev/null
+++ b/tests/ui/backtrace/synchronized-panic-handler.run.stderr
@@ -0,0 +1,5 @@
+thread '<unnamed>' panicked at $DIR/synchronized-panic-handler.rs:10:5:
+oops oh no woe is me
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+thread '<unnamed>' panicked at $DIR/synchronized-panic-handler.rs:10:5:
+oops oh no woe is me
diff --git a/tests/ui/borrowck/dbg-issue-120327.rs b/tests/ui/borrowck/dbg-issue-120327.rs
new file mode 100644
index 00000000000..2de43f63487
--- /dev/null
+++ b/tests/ui/borrowck/dbg-issue-120327.rs
@@ -0,0 +1,68 @@
+fn s() -> String {
+    let a = String::new();
+    dbg!(a);
+    return a; //~ ERROR use of moved value:
+}
+
+fn m() -> String {
+    let a = String::new();
+    dbg!(1, 2, a, 1, 2);
+    return a; //~ ERROR use of moved value:
+}
+
+fn t(a: String) -> String {
+    let b: String = "".to_string();
+    dbg!(a, b);
+    return b; //~ ERROR use of moved value:
+}
+
+fn x(a: String) -> String {
+    let b: String = "".to_string();
+    dbg!(a, b);
+    return a; //~ ERROR use of moved value:
+}
+
+macro_rules! my_dbg {
+    () => {
+        eprintln!("[{}:{}:{}]", file!(), line!(), column!())
+    };
+    ($val:expr $(,)?) => {
+        match $val {
+            tmp => {
+                eprintln!("[{}:{}:{}] {} = {:#?}",
+                    file!(), line!(), column!(), stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($(my_dbg!($val)),+,)
+    };
+}
+
+fn test_my_dbg() -> String {
+    let b: String = "".to_string();
+    my_dbg!(b, 1);
+    return b; //~ ERROR use of moved value:
+}
+
+fn test_not_macro() -> String {
+    let a = String::new();
+    let _b = match a {
+        tmp => {
+            eprintln!("dbg: {}", tmp);
+            tmp
+        }
+    };
+    return a; //~ ERROR use of moved value:
+}
+
+fn get_expr(_s: String) {}
+
+fn test() {
+    let a: String = "".to_string();
+    let _res = get_expr(dbg!(a));
+    let _l = a.len(); //~ ERROR borrow of moved value
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/dbg-issue-120327.stderr b/tests/ui/borrowck/dbg-issue-120327.stderr
new file mode 100644
index 00000000000..efacc0c3f13
--- /dev/null
+++ b/tests/ui/borrowck/dbg-issue-120327.stderr
@@ -0,0 +1,117 @@
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:4:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(a);
+   |     ------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(&a);
+   |          +
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:10:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(1, 2, a, 1, 2);
+   |     ------------------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(1, 2, &a, 1, 2);
+   |                +
+
+error[E0382]: use of moved value: `b`
+  --> $DIR/dbg-issue-120327.rs:16:12
+   |
+LL |     let b: String = "".to_string();
+   |         - move occurs because `b` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(a, b);
+   |     ---------- value moved here
+LL |     return b;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(a, &b);
+   |             +
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:22:12
+   |
+LL | fn x(a: String) -> String {
+   |      - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let b: String = "".to_string();
+LL |     dbg!(a, b);
+   |     ---------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(&a, b);
+   |          +
+
+error[E0382]: use of moved value: `b`
+  --> $DIR/dbg-issue-120327.rs:46:12
+   |
+LL |             tmp => {
+   |             --- value moved here
+...
+LL |     let b: String = "".to_string();
+   |         - move occurs because `b` has type `String`, which does not implement the `Copy` trait
+LL |     my_dbg!(b, 1);
+LL |     return b;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     my_dbg!(&b, 1);
+   |             +
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |             ref tmp => {
+   |             +++
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:57:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let _b = match a {
+LL |         tmp => {
+   |         --- value moved here
+...
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref tmp => {
+   |         +++
+
+error[E0382]: borrow of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:65:14
+   |
+LL |     let a: String = "".to_string();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let _res = get_expr(dbg!(a));
+   |                         ------- value moved here
+LL |     let _l = a.len();
+   |              ^ value borrowed here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     let _res = get_expr(dbg!(&a));
+   |                              +
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index cc63466585a..00a97ca1488 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`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, and `avxvnniint8` and 191 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 197 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 8a99ace75d8..78b7f0f5d99 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`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `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`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `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`, `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`, `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/issue-72408-nested-closures-exponential.rs b/tests/ui/closures/issue-72408-nested-closures-exponential.rs
index 033e4224338..45bc1ab5b1b 100644
--- a/tests/ui/closures/issue-72408-nested-closures-exponential.rs
+++ b/tests/ui/closures/issue-72408-nested-closures-exponential.rs
@@ -1,4 +1,4 @@
-//@ build-fail
+//@ check-pass
 
 // Closures include captured types twice in a type tree.
 //
@@ -45,7 +45,6 @@ fn main() {
 
     let f = dup(f);
     let f = dup(f);
-    //~^ ERROR reached the type-length limit
     let f = dup(f);
     let f = dup(f);
     let f = dup(f);
diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr
deleted file mode 100644
index 2120b456963..00000000000
--- a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: reached the type-length limit while instantiating `dup::<{closure@$DIR/issue-72408-nested-closures-exponential.rs:13:5: 13:13}>`
-  --> $DIR/issue-72408-nested-closures-exponential.rs:47:13
-   |
-LL |     let f = dup(f);
-   |             ^^^^^^
-   |
-   = help: consider adding a `#![type_length_limit="29360121"]` attribute to your crate
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs
index 4d3f2c18dc8..83a8b6b3ef6 100644
--- a/tests/ui/codegen/overflow-during-mono.rs
+++ b/tests/ui/codegen/overflow-during-mono.rs
@@ -1,5 +1,5 @@
+//~ ERROR overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized`
 //@ build-fail
-//@ error-pattern: reached the type-length limit while instantiating
 
 #![recursion_limit = "32"]
 
diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr
index e06fcd28966..f7a3e2df3db 100644
--- a/tests/ui/codegen/overflow-during-mono.stderr
+++ b/tests/ui/codegen/overflow-during-mono.stderr
@@ -1,8 +1,11 @@
-error: reached the type-length limit while instantiating `<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, ...> as Iterator>::try_fold::<..., ..., ...>`
-  --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
+error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized`
    |
-   = help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate
-   = note: the full type name has been written to '$TEST_BUILD_DIR/codegen/overflow-during-mono/overflow-during-mono.long-type.txt'
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`)
+   = note: required for `Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator`
+   = note: 31 redundant requirements hidden
+   = note: required for `Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator`
+   = note: required for `Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator`
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.stderr b/tests/ui/conditional-compilation/cfg-attr-parse.stderr
index 8084a622045..759df3c90c6 100644
--- a/tests/ui/conditional-compilation/cfg-attr-parse.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-parse.stderr
@@ -2,9 +2,13 @@ error: malformed `cfg_attr` attribute input
   --> $DIR/cfg-attr-parse.rs:4:1
    |
 LL | #[cfg_attr()]
-   | ^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+   | ^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+help: missing condition and attribute
+   |
+LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: expected `,`, found end of `cfg_attr` input
   --> $DIR/cfg-attr-parse.rs:8:17
diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr
index 83c71e07253..e9ea22e472c 100644
--- a/tests/ui/const-generics/legacy-const-generics-bad.stderr
+++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr
@@ -1,10 +1,13 @@
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/legacy-const-generics-bad.rs:7:35
    |
-LL |     let a = 1;
-   |     ----- help: consider using `const` instead of `let`: `const a`
 LL |     legacy_const_generics::foo(0, a, 2);
    |                                   ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const a: /* Type */ = 1;
+   |     ~~~~~  ++++++++++++
 
 error: generic parameters may not be used in const operations
   --> $DIR/legacy-const-generics-bad.rs:12:35
diff --git a/tests/ui/consts/const-eval/issue-104390.stderr b/tests/ui/consts/const-eval/issue-104390.stderr
index 865b9996ea3..4c425ecfc13 100644
--- a/tests/ui/consts/const-eval/issue-104390.stderr
+++ b/tests/ui/consts/const-eval/issue-104390.stderr
@@ -38,28 +38,43 @@ error: borrow expressions cannot be annotated with lifetimes
   --> $DIR/issue-104390.rs:3:25
    |
 LL | fn f3() -> impl Sized { &'a 2E }
-   |                         ^--^^^
+   |                         ^---^^
    |                          |
    |                          annotated with lifetime here
-   |                          help: remove the lifetime annotation
+   |
+help: remove the lifetime annotation
+   |
+LL - fn f3() -> impl Sized { &'a 2E }
+LL + fn f3() -> impl Sized { &2E }
+   |
 
 error: borrow expressions cannot be annotated with lifetimes
   --> $DIR/issue-104390.rs:5:25
    |
 LL | fn f4() -> impl Sized { &'static 2E }
-   |                         ^-------^^^
+   |                         ^--------^^
    |                          |
    |                          annotated with lifetime here
-   |                          help: remove the lifetime annotation
+   |
+help: remove the lifetime annotation
+   |
+LL - fn f4() -> impl Sized { &'static 2E }
+LL + fn f4() -> impl Sized { &2E }
+   |
 
 error: borrow expressions cannot be annotated with lifetimes
   --> $DIR/issue-104390.rs:8:25
    |
 LL | fn f6() -> impl Sized { &'_ 2E }
-   |                         ^--^^^
+   |                         ^---^^
    |                          |
    |                          annotated with lifetime here
-   |                          help: remove the lifetime annotation
+   |
+help: remove the lifetime annotation
+   |
+LL - fn f6() -> impl Sized { &'_ 2E }
+LL + fn f6() -> impl Sized { &2E }
+   |
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/consts/issue-3521.stderr b/tests/ui/consts/issue-3521.stderr
index 70ce9b2d6a0..c0e4cdc5a94 100644
--- a/tests/ui/consts/issue-3521.stderr
+++ b/tests/ui/consts/issue-3521.stderr
@@ -1,11 +1,13 @@
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-3521.rs:8:15
    |
-LL |     let foo: isize = 100;
-   |     ------- help: consider using `const` instead of `let`: `const foo`
-...
 LL |         Bar = foo
    |               ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: isize = 100;
+   |     ~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-91560.stderr b/tests/ui/consts/issue-91560.stderr
index e1b5d4cacf8..37c8f50d494 100644
--- a/tests/ui/consts/issue-91560.stderr
+++ b/tests/ui/consts/issue-91560.stderr
@@ -1,20 +1,24 @@
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-91560.rs:10:19
    |
-LL |     let mut length: usize = 2;
-   |     -------------- help: consider using `const` instead of `let`: `const length`
-LL |
 LL |     let arr = [0; length];
    |                   ^^^^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const length: usize = 2;
+   |     ~~~~~
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-91560.rs:17:19
    |
-LL |     let   length: usize = 2;
-   |     ------------ help: consider using `const` instead of `let`: `const length`
-LL |
 LL |     let arr = [0; length];
    |                   ^^^^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const length: usize = 2;
+   |     ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs
index efb346f91ae..7e759a1a1e4 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references.rs
+++ b/tests/ui/consts/miri_unleashed/mutable_references.rs
@@ -2,13 +2,20 @@
 //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
 //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 
+#![allow(static_mut_refs)]
 #![deny(const_eval_mutable_ptr_in_final_value)]
 use std::cell::UnsafeCell;
+use std::sync::atomic::*;
+
+// # Plain `&mut` in the final value
 
 // This requires walking nested statics.
 static FOO: &&mut u32 = &&mut 42;
 //~^ ERROR it is undefined behavior to use this value
-
+//~| pointing to read-only memory
+static OH_YES: &mut i32 = &mut 42;
+//~^ ERROR it is undefined behavior to use this value
+//~| pointing to read-only memory
 static BAR: &mut () = &mut ();
 //~^ ERROR encountered mutable pointer in final value of static
 //~| WARNING this was previously accepted by the compiler
@@ -19,15 +26,92 @@ static BOO: &mut Foo<()> = &mut Foo(());
 //~^ ERROR encountered mutable pointer in final value of static
 //~| WARNING this was previously accepted by the compiler
 
+const BLUNT: &mut i32 = &mut 42;
+//~^ ERROR: it is undefined behavior to use this value
+//~| pointing to read-only memory
+
+const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC };
+//~^ ERROR: it is undefined behavior to use this value
+//~| static
+
+// # Interior mutability
+
 struct Meh {
     x: &'static UnsafeCell<i32>,
 }
 unsafe impl Sync for Meh {}
 static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
 //~^ ERROR it is undefined behavior to use this value
+//~| `UnsafeCell` in read-only memory
+// Same with a const:
+// the following will never be ok! no interior mut behind consts, because
+// all allocs interned here will be marked immutable.
+const MUH: Meh = Meh {
+    //~^ ERROR it is undefined behavior to use this value
+    //~| `UnsafeCell` in read-only memory
+    x: &UnsafeCell::new(42),
+};
+
+struct Synced {
+    x: UnsafeCell<i32>,
+}
+unsafe impl Sync for Synced {}
+
+// Make sure we also catch this behind a type-erased `dyn Trait` reference.
+const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
+//~^ ERROR: it is undefined behavior to use this value
+//~| `UnsafeCell` in read-only memory
+
+// # Check for mutable references to read-only memory
+
+static READONLY: i32 = 0;
+static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
+//~^ ERROR: it is undefined behavior to use this value
+//~| pointing to read-only memory
+
+// # Check for consts pointing to mutable memory
+
+static mut MUTABLE: i32 = 42;
+const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; //~ERROR: undefined behavior
+//~| encountered reference to mutable memory
+static mut MUTABLE_REF: &mut i32 = &mut 42;
+const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
+//~^ ERROR: evaluation of constant value failed
+//~| accesses mutable global memory
+
+const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
+//~^ ERROR: mutable pointer in final value
+//~| WARNING this was previously accepted by the compiler
+
+const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
+//~^ ERROR: mutable pointer in final value
+//~| WARNING this was previously accepted by the compiler
+
+const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
+//~^ ERROR: mutable pointer in final value
+//~| WARNING this was previously accepted by the compiler
+
+struct SyncPtr<T> {
+    x: *const T,
+}
+unsafe impl<T> Sync for SyncPtr<T> {}
+
+// These pass the lifetime checks because of the "tail expression" / "outer scope" rule.
+// (This relies on `SyncPtr` being a curly brace struct.)
+// However, we intern the inner memory as read-only, so this must be rejected.
+// (Also see `static-no-inner-mut` for similar tests on `static`.)
+const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
+//~^ ERROR mutable pointer in final value
+//~| WARNING this was previously accepted by the compiler
+
+const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
+//~^ ERROR mutable pointer in final value
+//~| WARNING this was previously accepted by the compiler
+
+const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
+//~^ ERROR mutable pointer in final value
+//~| WARNING this was previously accepted by the compiler
 
-static OH_YES: &mut i32 = &mut 42;
-//~^ ERROR it is undefined behavior to use this value
 
 fn main() {
     unsafe {
diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr
index b207e3869ac..620953ffa3e 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references.stderr
+++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references.rs:9:1
+  --> $DIR/mutable_references.rs:13:1
    |
 LL | static FOO: &&mut u32 = &&mut 42;
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered mutable reference or box pointing to read-only memory
@@ -9,8 +9,19 @@ LL | static FOO: &&mut u32 = &&mut 42;
                HEX_DUMP
            }
 
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/mutable_references.rs:16:1
+   |
+LL | static OH_YES: &mut i32 = &mut 42;
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
 error: encountered mutable pointer in final value of static
-  --> $DIR/mutable_references.rs:12:1
+  --> $DIR/mutable_references.rs:19:1
    |
 LL | static BAR: &mut () = &mut ();
    | ^^^^^^^^^^^^^^^^^^^
@@ -18,13 +29,13 @@ LL | static BAR: &mut () = &mut ();
    = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
 note: the lint level is defined here
-  --> $DIR/mutable_references.rs:5:9
+  --> $DIR/mutable_references.rs:6:9
    |
 LL | #![deny(const_eval_mutable_ptr_in_final_value)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: encountered mutable pointer in final value of static
-  --> $DIR/mutable_references.rs:18:1
+  --> $DIR/mutable_references.rs:25:1
    |
 LL | static BOO: &mut Foo<()> = &mut Foo(());
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +44,29 @@ LL | static BOO: &mut Foo<()> = &mut Foo(());
    = note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references.rs:26:1
+  --> $DIR/mutable_references.rs:29:1
+   |
+LL | const BLUNT: &mut i32 = &mut 42;
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/mutable_references.rs:33:1
+   |
+LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC };
+   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/mutable_references.rs:43:1
    |
 LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
    | ^^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in read-only memory
@@ -44,18 +77,111 @@ LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references.rs:29:1
+  --> $DIR/mutable_references.rs:49:1
    |
-LL | static OH_YES: &mut i32 = &mut 42;
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
+LL | const MUH: Meh = Meh {
+   | ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in read-only memory
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/mutable_references.rs:61:1
+   |
+LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in read-only memory
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
                HEX_DUMP
            }
 
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/mutable_references.rs:68:1
+   |
+LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/mutable_references.rs:75:1
+   |
+LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/mutable_references.rs:78:43
+   |
+LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
+   |                                           ^^^^^^^^^^^^^ constant accesses mutable global memory
+
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:82:1
+   |
+LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:86:1
+   |
+LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:90:1
+   |
+LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:103:1
+   |
+LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:107:1
+   |
+LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:111:1
+   |
+LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+
 error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item
-  --> $DIR/mutable_references.rs:36:5
+  --> $DIR/mutable_references.rs:120:5
    |
 LL |     *OH_YES = 99;
    |     ^^^^^^^^^^^^ cannot assign
@@ -63,38 +189,113 @@ LL |     *OH_YES = 99;
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references.rs:9:26
+  --> $DIR/mutable_references.rs:13:26
    |
 LL | static FOO: &&mut u32 = &&mut 42;
    |                          ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references.rs:12:23
+  --> $DIR/mutable_references.rs:16:27
+   |
+LL | static OH_YES: &mut i32 = &mut 42;
+   |                           ^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:19:23
    |
 LL | static BAR: &mut () = &mut ();
    |                       ^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references.rs:18:28
+  --> $DIR/mutable_references.rs:25:28
    |
 LL | static BOO: &mut Foo<()> = &mut Foo(());
    |                            ^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references.rs:26:28
+  --> $DIR/mutable_references.rs:29:25
+   |
+LL | const BLUNT: &mut i32 = &mut 42;
+   |                         ^^^^^^^
+help: skipping check for `const_refs_to_static` feature
+  --> $DIR/mutable_references.rs:33:68
+   |
+LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC };
+   |                                                                    ^^^^^^
+help: skipping check for `const_mut_refs` feature
+  --> $DIR/mutable_references.rs:33:63
+   |
+LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC };
+   |                                                               ^^^^^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:43:28
    |
 LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
    |                            ^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references.rs:29:27
+  --> $DIR/mutable_references.rs:52:8
    |
-LL | static OH_YES: &mut i32 = &mut 42;
-   |                           ^^^^^^^
+LL |     x: &UnsafeCell::new(42),
+   |        ^^^^^^^^^^^^^^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:61:27
+   |
+LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: skipping check for `const_mut_refs` feature
+  --> $DIR/mutable_references.rs:68:49
+   |
+LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: skipping check for `const_mut_refs` feature
+  --> $DIR/mutable_references.rs:68:49
+   |
+LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: skipping check for `const_refs_to_static` feature
+  --> $DIR/mutable_references.rs:75:43
+   |
+LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE };
+   |                                           ^^^^^^^
+help: skipping check for `const_refs_to_static` feature
+  --> $DIR/mutable_references.rs:78:45
+   |
+LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
+   |                                             ^^^^^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:82:45
+   |
+LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
+   |                                             ^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:86:46
+   |
+LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
+   |                                              ^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:90:47
+   |
+LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
+   |                                               ^^^^^^^^^^^^^^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:103:51
+   |
+LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
+   |                                                   ^^^^^^^^^^^^^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:107:49
+   |
+LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
+   |                                                 ^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/mutable_references.rs:111:51
+   |
+LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
+   |                                                   ^^^^^^
 
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 19 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0080, E0594.
 For more information about an error, try `rustc --explain E0080`.
 Future incompatibility report: Future breakage diagnostic:
 error: encountered mutable pointer in final value of static
-  --> $DIR/mutable_references.rs:12:1
+  --> $DIR/mutable_references.rs:19:1
    |
 LL | static BAR: &mut () = &mut ();
    | ^^^^^^^^^^^^^^^^^^^
@@ -102,14 +303,14 @@ LL | static BAR: &mut () = &mut ();
    = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
 note: the lint level is defined here
-  --> $DIR/mutable_references.rs:5:9
+  --> $DIR/mutable_references.rs:6:9
    |
 LL | #![deny(const_eval_mutable_ptr_in_final_value)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
 error: encountered mutable pointer in final value of static
-  --> $DIR/mutable_references.rs:18:1
+  --> $DIR/mutable_references.rs:25:1
    |
 LL | static BOO: &mut Foo<()> = &mut Foo(());
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +318,97 @@ LL | static BOO: &mut Foo<()> = &mut Foo(());
    = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
 note: the lint level is defined here
-  --> $DIR/mutable_references.rs:5:9
+  --> $DIR/mutable_references.rs:6:9
+   |
+LL | #![deny(const_eval_mutable_ptr_in_final_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:82:1
+   |
+LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+note: the lint level is defined here
+  --> $DIR/mutable_references.rs:6:9
+   |
+LL | #![deny(const_eval_mutable_ptr_in_final_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:86:1
+   |
+LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+note: the lint level is defined here
+  --> $DIR/mutable_references.rs:6:9
+   |
+LL | #![deny(const_eval_mutable_ptr_in_final_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:90:1
+   |
+LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+note: the lint level is defined here
+  --> $DIR/mutable_references.rs:6:9
+   |
+LL | #![deny(const_eval_mutable_ptr_in_final_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:103:1
+   |
+LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+note: the lint level is defined here
+  --> $DIR/mutable_references.rs:6:9
+   |
+LL | #![deny(const_eval_mutable_ptr_in_final_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:107:1
+   |
+LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+note: the lint level is defined here
+  --> $DIR/mutable_references.rs:6:9
+   |
+LL | #![deny(const_eval_mutable_ptr_in_final_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: encountered mutable pointer in final value of constant
+  --> $DIR/mutable_references.rs:111:1
+   |
+LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
+note: the lint level is defined here
+  --> $DIR/mutable_references.rs:6:9
    |
 LL | #![deny(const_eval_mutable_ptr_in_final_value)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.rs b/tests/ui/consts/miri_unleashed/mutable_references_err.rs
deleted file mode 100644
index 8398b0758dd..00000000000
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-//@ compile-flags: -Zunleash-the-miri-inside-of-you
-//@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
-//@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
-#![allow(invalid_reference_casting, static_mut_refs)]
-#![deny(const_eval_mutable_ptr_in_final_value)]
-use std::cell::UnsafeCell;
-use std::sync::atomic::*;
-
-// this test ensures that our mutability story is sound
-
-struct Meh {
-    x: &'static UnsafeCell<i32>,
-}
-unsafe impl Sync for Meh {}
-
-// the following will never be ok! no interior mut behind consts, because
-// all allocs interned here will be marked immutable.
-const MUH: Meh = Meh {
-    //~^ ERROR it is undefined behavior to use this value
-    x: &UnsafeCell::new(42),
-};
-
-struct Synced {
-    x: UnsafeCell<i32>,
-}
-unsafe impl Sync for Synced {}
-
-// Make sure we also catch this behind a type-erased `dyn Trait` reference.
-const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
-//~^ ERROR: it is undefined behavior to use this value
-
-// Make sure we also catch mutable references in values that shouldn't have them.
-static mut FOO: i32 = 0;
-const SUBTLE: &mut i32 = unsafe { &mut FOO };
-//~^ ERROR: it is undefined behavior to use this value
-//~| static
-
-const BLUNT: &mut i32 = &mut 42;
-//~^ ERROR: it is undefined behavior to use this value
-
-// Check for mutable references to read-only memory.
-static READONLY: i32 = 0;
-static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
-//~^ ERROR: it is undefined behavior to use this value
-//~| pointing to read-only memory
-
-// Check for consts pointing to mutable memory.
-// These are fine as long as they are not being read.
-static mut MUTABLE: i32 = 42;
-const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; //~ERROR: undefined behavior
-//~| encountered reference to mutable memory
-const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1;
-static mut MUTABLE_REF: &mut i32 = &mut 42;
-const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
-//~^ ERROR: evaluation of constant value failed
-//~| accesses mutable global memory
-
-const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
-//~^ ERROR: mutable pointer in final value
-//~| WARNING this was previously accepted by the compiler
-
-const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
-//~^ ERROR: mutable pointer in final value
-//~| WARNING this was previously accepted by the compiler
-
-const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-//~^ ERROR: mutable pointer in final value
-//~| WARNING this was previously accepted by the compiler
-
-struct SyncPtr<T> {
-    x: *const T,
-}
-unsafe impl<T> Sync for SyncPtr<T> {}
-
-// These pass the lifetime checks because of the "tail expression" / "outer scope" rule.
-// (This relies on `SyncPtr` being a curly brace struct.)
-// However, we intern the inner memory as read-only, so this must be rejected.
-// (Also see `static-no-inner-mut` for similar tests on `static`.)
-const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
-//~^ ERROR mutable pointer in final value
-//~| WARNING this was previously accepted by the compiler
-
-const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
-//~^ ERROR mutable pointer in final value
-//~| WARNING this was previously accepted by the compiler
-
-const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
-//~^ ERROR mutable pointer in final value
-//~| WARNING this was previously accepted by the compiler
-
-fn main() {
-    unsafe {
-        *MUH.x.get() = 99;
-    }
-}
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.stderr
deleted file mode 100644
index d385b45a3df..00000000000
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.stderr
+++ /dev/null
@@ -1,308 +0,0 @@
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:18:1
-   |
-LL | const MUH: Meh = Meh {
-   | ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in read-only memory
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
-               HEX_DUMP
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:29:1
-   |
-LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in read-only memory
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
-               HEX_DUMP
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:34:1
-   |
-LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
-   | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
-               HEX_DUMP
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:38:1
-   |
-LL | const BLUNT: &mut i32 = &mut 42;
-   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
-               HEX_DUMP
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:43:1
-   |
-LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
-               HEX_DUMP
-           }
-
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/mutable_references_err.rs:50:1
-   |
-LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
-               HEX_DUMP
-           }
-
-note: erroneous constant encountered
-  --> $DIR/mutable_references_err.rs:52:34
-   |
-LL | const READS_FROM_MUTABLE: i32 = *POINTS_TO_MUTABLE1;
-   |                                  ^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/mutable_references_err.rs:54:43
-   |
-LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
-   |                                           ^^^^^^^^^^^^^ constant accesses mutable global memory
-
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:58:1
-   |
-LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-note: the lint level is defined here
-  --> $DIR/mutable_references_err.rs:5:9
-   |
-LL | #![deny(const_eval_mutable_ptr_in_final_value)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:62:1
-   |
-LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:66:1
-   |
-LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:79:1
-   |
-LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:83:1
-   |
-LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:87:1
-   |
-LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-
-warning: skipping const checks
-   |
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:20:8
-   |
-LL |     x: &UnsafeCell::new(42),
-   |        ^^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:29:27
-   |
-LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:34:40
-   |
-LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
-   |                                        ^^^
-help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:34:35
-   |
-LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
-   |                                   ^^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:38:25
-   |
-LL | const BLUNT: &mut i32 = &mut 42;
-   |                         ^^^^^^^
-help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:43:49
-   |
-LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_mut_refs` feature
-  --> $DIR/mutable_references_err.rs:43:49
-   |
-LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) };
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:50:44
-   |
-LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
-   |                                            ^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:54:45
-   |
-LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
-   |                                             ^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:58:45
-   |
-LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
-   |                                             ^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:62:46
-   |
-LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
-   |                                              ^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:66:47
-   |
-LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-   |                                               ^^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:79:51
-   |
-LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
-   |                                                   ^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:83:49
-   |
-LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
-   |                                                 ^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/mutable_references_err.rs:87:51
-   |
-LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
-   |                                                   ^^^^^^
-
-error: aborting due to 13 previous errors; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0080`.
-Future incompatibility report: Future breakage diagnostic:
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:58:1
-   |
-LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-note: the lint level is defined here
-  --> $DIR/mutable_references_err.rs:5:9
-   |
-LL | #![deny(const_eval_mutable_ptr_in_final_value)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:62:1
-   |
-LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-note: the lint level is defined here
-  --> $DIR/mutable_references_err.rs:5:9
-   |
-LL | #![deny(const_eval_mutable_ptr_in_final_value)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:66:1
-   |
-LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-note: the lint level is defined here
-  --> $DIR/mutable_references_err.rs:5:9
-   |
-LL | #![deny(const_eval_mutable_ptr_in_final_value)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:79:1
-   |
-LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-note: the lint level is defined here
-  --> $DIR/mutable_references_err.rs:5:9
-   |
-LL | #![deny(const_eval_mutable_ptr_in_final_value)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:83:1
-   |
-LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x: &mut 42 as *mut _ as *const _ };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-note: the lint level is defined here
-  --> $DIR/mutable_references_err.rs:5:9
-   |
-LL | #![deny(const_eval_mutable_ptr_in_final_value)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: encountered mutable pointer in final value of constant
-  --> $DIR/mutable_references_err.rs:87:1
-   |
-LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #122153 <https://github.com/rust-lang/rust/issues/122153>
-note: the lint level is defined here
-  --> $DIR/mutable_references_err.rs:5:9
-   |
-LL | #![deny(const_eval_mutable_ptr_in_final_value)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
diff --git a/tests/ui/consts/non-const-value-in-const.stderr b/tests/ui/consts/non-const-value-in-const.stderr
index 0ce4b4b7053..654b573544c 100644
--- a/tests/ui/consts/non-const-value-in-const.stderr
+++ b/tests/ui/consts/non-const-value-in-const.stderr
@@ -2,18 +2,23 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/non-const-value-in-const.rs:3:20
    |
 LL |     const Y: i32 = x;
-   |     -------        ^ non-constant value
-   |     |
-   |     help: consider using `let` instead of `const`: `let Y`
+   |                    ^ non-constant value
+   |
+help: consider using `let` instead of `const`
+   |
+LL |     let Y: i32 = x;
+   |     ~~~
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/non-const-value-in-const.rs:6:17
    |
-LL |     let x = 5;
-   |     ----- help: consider using `const` instead of `let`: `const x`
-...
 LL |     let _ = [0; x];
    |                 ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const x: /* Type */ = 5;
+   |     ~~~~~  ++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs
index e71f88b8d5f..1506c212fba 100644
--- a/tests/ui/consts/offset_from_ub.rs
+++ b/tests/ui/consts/offset_from_ub.rs
@@ -32,12 +32,6 @@ pub const NOT_MULTIPLE_OF_SIZE: isize = {
     //~| 1_isize cannot be divided by 2_isize without remainder
 };
 
-pub const OFFSET_FROM_NULL: isize = {
-    let ptr = 0 as *const u8;
-    // Null isn't special for zero-sized "accesses" (i.e., the range between the two pointers)
-    unsafe { ptr_offset_from(ptr, ptr) }
-};
-
 pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC
     let ptr1 = 8 as *const u8;
     let ptr2 = 16 as *const u8;
@@ -63,14 +57,6 @@ const OUT_OF_BOUNDS_2: isize = {
     //~| pointer to 10 bytes starting at offset 0 is out-of-bounds
 };
 
-const OUT_OF_BOUNDS_SAME: isize = {
-    let start_ptr = &4 as *const _ as *const u8;
-    let length = 10;
-    let end_ptr = (start_ptr).wrapping_add(length);
-    // Out-of-bounds is fine as long as the range between the pointers is empty.
-    unsafe { ptr_offset_from(end_ptr, end_ptr) }
-};
-
 pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
     let uninit = std::mem::MaybeUninit::<Struct>::uninit();
     let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
@@ -130,4 +116,23 @@ pub const OFFSET_VERY_FAR2: isize = {
     //~^ inside
 };
 
+// If the pointers are the same, OOB/null/UAF is fine.
+pub const OFFSET_FROM_NULL_SAME: isize = {
+    let ptr = 0 as *const u8;
+    unsafe { ptr_offset_from(ptr, ptr) }
+};
+const OUT_OF_BOUNDS_SAME: isize = {
+    let start_ptr = &4 as *const _ as *const u8;
+    let length = 10;
+    let end_ptr = (start_ptr).wrapping_add(length);
+    unsafe { ptr_offset_from(end_ptr, end_ptr) }
+};
+const UAF_SAME: isize = {
+    let uaf_ptr = {
+        let x = 0;
+        &x as *const i32
+    };
+    unsafe { ptr_offset_from(uaf_ptr, uaf_ptr) }
+};
+
 fn main() {}
diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr
index 7caf6247b9e..7b623126d54 100644
--- a/tests/ui/consts/offset_from_ub.stderr
+++ b/tests/ui/consts/offset_from_ub.stderr
@@ -24,55 +24,55 @@ LL |     unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:44:14
+  --> $DIR/offset_from_ub.rs:38:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:53:14
+  --> $DIR/offset_from_ub.rs:47:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, start_ptr) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC0 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:62:14
+  --> $DIR/offset_from_ub.rs:56:14
    |
 LL |     unsafe { ptr_offset_from(start_ptr, end_ptr) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC1 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:79:14
+  --> $DIR/offset_from_ub.rs:65:14
    |
 LL |     unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:86:14
+  --> $DIR/offset_from_ub.rs:72:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:92:14
+  --> $DIR/offset_from_ub.rs:78:14
    |
 LL |     unsafe { ptr_offset_from(ptr1, ptr2) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:100:14
+  --> $DIR/offset_from_ub.rs:86:14
    |
 LL |     unsafe { ptr_offset_from(ptr1, ptr2) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:107:14
+  --> $DIR/offset_from_ub.rs:93:14
    |
 LL |     unsafe { ptr_offset_from_unsigned(p, p.add(2) ) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:114:14
+  --> $DIR/offset_from_ub.rs:100:14
    |
 LL |     unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second
@@ -85,7 +85,7 @@ error[E0080]: evaluation of constant value failed
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `OFFSET_VERY_FAR1`
-  --> $DIR/offset_from_ub.rs:123:14
+  --> $DIR/offset_from_ub.rs:109:14
    |
 LL |     unsafe { ptr2.offset_from(ptr1) }
    |              ^^^^^^^^^^^^^^^^^^^^^^
@@ -98,7 +98,7 @@ error[E0080]: evaluation of constant value failed
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `OFFSET_VERY_FAR2`
-  --> $DIR/offset_from_ub.rs:129:14
+  --> $DIR/offset_from_ub.rs:115:14
    |
 LL |     unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr
index a5868fcf19c..2bcf54860eb 100644
--- a/tests/ui/coverage-attr/bad-syntax.stderr
+++ b/tests/ui/coverage-attr/bad-syntax.stderr
@@ -106,10 +106,13 @@ error: expected identifier, found `,`
   --> $DIR/bad-syntax.rs:42:12
    |
 LL | #[coverage(,off)]
-   |            ^
-   |            |
-   |            expected identifier
-   |            help: remove this comma
+   |            ^ expected identifier
+   |
+help: remove this comma
+   |
+LL - #[coverage(,off)]
+LL + #[coverage(off)]
+   |
 
 error: multiple `coverage` attributes
   --> $DIR/bad-syntax.rs:7:1
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr
new file mode 100644
index 00000000000..629fc59361d
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `(): Foo` is not satisfied
+  --> $DIR/supress_suggestions_in_help.rs:23:11
+   |
+LL |     check(());
+   |     ----- ^^ the trait `Foo` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Foo` is implemented for `i32`
+note: required by a bound in `check`
+  --> $DIR/supress_suggestions_in_help.rs:20:18
+   |
+LL | fn check(a: impl Foo) {}
+   |                  ^^^ required by this bound in `check`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr
new file mode 100644
index 00000000000..629fc59361d
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `(): Foo` is not satisfied
+  --> $DIR/supress_suggestions_in_help.rs:23:11
+   |
+LL |     check(());
+   |     ----- ^^ the trait `Foo` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Foo` is implemented for `i32`
+note: required by a bound in `check`
+  --> $DIR/supress_suggestions_in_help.rs:20:18
+   |
+LL | fn check(a: impl Foo) {}
+   |                  ^^^ required by this bound in `check`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs
new file mode 100644
index 00000000000..ef6f255c351
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs
@@ -0,0 +1,25 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+#![feature(do_not_recommend)]
+
+trait Foo {}
+
+#[diagnostic::do_not_recommend]
+impl<A> Foo for (A,) {}
+
+#[diagnostic::do_not_recommend]
+impl<A, B> Foo for (A, B) {}
+
+#[diagnostic::do_not_recommend]
+impl<A, B, C> Foo for (A, B, C) {}
+
+impl Foo for i32 {}
+
+fn check(a: impl Foo) {}
+
+fn main() {
+    check(());
+    //~^ ERROR the trait bound `(): Foo` is not satisfied
+}
diff --git a/tests/ui/did_you_mean/E0178.stderr b/tests/ui/did_you_mean/E0178.stderr
index 58ac6e90823..5f289da8a6c 100644
--- a/tests/ui/did_you_mean/E0178.stderr
+++ b/tests/ui/did_you_mean/E0178.stderr
@@ -2,19 +2,34 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`
   --> $DIR/E0178.rs:6:8
    |
 LL |     w: &'a Foo + Copy,
-   |        ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)`
+   |        ^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL |     w: &'a (Foo + Copy),
+   |            +          +
 
 error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`
   --> $DIR/E0178.rs:7:8
    |
 LL |     x: &'a Foo + 'a,
-   |        ^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + 'a)`
+   |        ^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL |     x: &'a (Foo + 'a),
+   |            +        +
 
 error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo`
   --> $DIR/E0178.rs:8:8
    |
 LL |     y: &'a mut Foo + 'a,
-   |        ^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'a mut (Foo + 'a)`
+   |        ^^^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL |     y: &'a mut (Foo + 'a),
+   |                +        +
 
 error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo`
   --> $DIR/E0178.rs:9:8
diff --git a/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr b/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr
index 2a3242abea4..952ac76a003 100644
--- a/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr
+++ b/tests/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr
@@ -2,39 +2,56 @@ error: `~` cannot be used as a unary operator
   --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:4:14
    |
 LL |     let _x = ~1;
-   |              ^ help: use `!` to perform bitwise not
+   |              ^
+   |
+help: use `!` to perform bitwise not
+   |
+LL |     let _x = !1;
+   |              ~
 
 error: unexpected `1` after identifier
   --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:5:18
    |
 LL |     let _y = not 1;
-   |              ----^
-   |              |
-   |              help: use `!` to perform bitwise not
+   |                  ^
+   |
+help: use `!` to perform bitwise not
+   |
+LL |     let _y = !1;
+   |              ~
 
 error: unexpected keyword `false` after identifier
   --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:6:18
    |
 LL |     let _z = not false;
-   |              ----^^^^^
-   |              |
-   |              help: use `!` to perform logical negation
+   |                  ^^^^^
+   |
+help: use `!` to perform logical negation
+   |
+LL |     let _z = !false;
+   |              ~
 
 error: unexpected keyword `true` after identifier
   --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:7:18
    |
 LL |     let _a = not true;
-   |              ----^^^^
-   |              |
-   |              help: use `!` to perform logical negation
+   |                  ^^^^
+   |
+help: use `!` to perform logical negation
+   |
+LL |     let _a = !true;
+   |              ~
 
 error: unexpected `v` after identifier
   --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:9:18
    |
 LL |     let _v = not v;
-   |              ----^
-   |              |
-   |              help: use `!` to perform logical negation or bitwise not
+   |                  ^
+   |
+help: use `!` to perform logical negation or bitwise not
+   |
+LL |     let _v = !v;
+   |              ~
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr
index 14918ba8953..6dea6a4fac8 100644
--- a/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr
+++ b/tests/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr
@@ -2,25 +2,34 @@ error: unexpected `for_you` after identifier
   --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:3:12
    |
 LL |     if not for_you {
-   |        ----^^^^^^^
-   |        |
-   |        help: use `!` to perform logical negation or bitwise not
+   |            ^^^^^^^
+   |
+help: use `!` to perform logical negation or bitwise not
+   |
+LL |     if !for_you {
+   |        ~
 
 error: unexpected `the_worst` after identifier
   --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:11:15
    |
 LL |     while not the_worst {
-   |           ----^^^^^^^^^
-   |           |
-   |           help: use `!` to perform logical negation or bitwise not
+   |               ^^^^^^^^^
+   |
+help: use `!` to perform logical negation or bitwise not
+   |
+LL |     while !the_worst {
+   |           ~
 
 error: unexpected `println` after identifier
   --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:9
    |
-LL |     if not  // lack of braces is [sic]
-   |        ----- help: use `!` to perform logical negation or bitwise not
 LL |         println!("Then when?");
    |         ^^^^^^^
+   |
+help: use `!` to perform logical negation or bitwise not
+   |
+LL |     if !// lack of braces is [sic]
+   |        ~
 
 error: expected `{`, found `;`
   --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:31
@@ -40,17 +49,23 @@ error: unexpected `2` after identifier
   --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24
    |
 LL |     let resource = not 2;
-   |                    ----^
-   |                    |
-   |                    help: use `!` to perform bitwise not
+   |                        ^
+   |
+help: use `!` to perform bitwise not
+   |
+LL |     let resource = !2;
+   |                    ~
 
 error: unexpected `be_smothered_out_before` after identifier
   --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:32:27
    |
 LL |     let young_souls = not be_smothered_out_before;
-   |                       ----^^^^^^^^^^^^^^^^^^^^^^^
-   |                       |
-   |                       help: use `!` to perform logical negation or bitwise not
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `!` to perform logical negation or bitwise not
+   |
+LL |     let young_souls = !be_smothered_out_before;
+   |                       ~
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr b/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr
index cbe59e8e0af..c52102e2631 100644
--- a/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr
+++ b/tests/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr
@@ -2,65 +2,97 @@ error: `and` is not a logical operator
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15
    |
 LL |     let _ = a and b;
-   |               ^^^ help: use `&&` to perform logical conjunction
+   |               ^^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `&&` to perform logical conjunction
+   |
+LL |     let _ = a && b;
+   |               ~~
 
 error: `and` is not a logical operator
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10
    |
 LL |     if a and b {
-   |          ^^^ help: use `&&` to perform logical conjunction
+   |          ^^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `&&` to perform logical conjunction
+   |
+LL |     if a && b {
+   |          ~~
 
 error: `or` is not a logical operator
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15
    |
 LL |     let _ = a or b;
-   |               ^^ help: use `||` to perform logical disjunction
+   |               ^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `||` to perform logical disjunction
+   |
+LL |     let _ = a || b;
+   |               ~~
 
 error: `or` is not a logical operator
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10
    |
 LL |     if a or b {
-   |          ^^ help: use `||` to perform logical disjunction
+   |          ^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `||` to perform logical disjunction
+   |
+LL |     if a || b {
+   |          ~~
 
 error: `and` is not a logical operator
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11
    |
 LL |     if (a and b) {
-   |           ^^^ help: use `&&` to perform logical conjunction
+   |           ^^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `&&` to perform logical conjunction
+   |
+LL |     if (a && b) {
+   |           ~~
 
 error: `or` is not a logical operator
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11
    |
 LL |     if (a or b) {
-   |           ^^ help: use `||` to perform logical disjunction
+   |           ^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `||` to perform logical disjunction
+   |
+LL |     if (a || b) {
+   |           ~~
 
 error: `and` is not a logical operator
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13
    |
 LL |     while a and b {
-   |             ^^^ help: use `&&` to perform logical conjunction
+   |             ^^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `&&` to perform logical conjunction
+   |
+LL |     while a && b {
+   |             ~~
 
 error: `or` is not a logical operator
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13
    |
 LL |     while a or b {
-   |             ^^ help: use `||` to perform logical disjunction
+   |             ^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `||` to perform logical disjunction
+   |
+LL |     while a || b {
+   |             ~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33
diff --git a/tests/ui/did_you_mean/issue-54109-without-witness.stderr b/tests/ui/did_you_mean/issue-54109-without-witness.stderr
index 6455b0863f8..ee6d9901fcf 100644
--- a/tests/ui/did_you_mean/issue-54109-without-witness.stderr
+++ b/tests/ui/did_you_mean/issue-54109-without-witness.stderr
@@ -2,65 +2,97 @@ error: `and` is not a logical operator
   --> $DIR/issue-54109-without-witness.rs:13:15
    |
 LL |     let _ = a and b;
-   |               ^^^ help: use `&&` to perform logical conjunction
+   |               ^^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `&&` to perform logical conjunction
+   |
+LL |     let _ = a && b;
+   |               ~~
 
 error: `and` is not a logical operator
   --> $DIR/issue-54109-without-witness.rs:15:10
    |
 LL |     if a and b {
-   |          ^^^ help: use `&&` to perform logical conjunction
+   |          ^^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `&&` to perform logical conjunction
+   |
+LL |     if a && b {
+   |          ~~
 
 error: `or` is not a logical operator
   --> $DIR/issue-54109-without-witness.rs:24:15
    |
 LL |     let _ = a or b;
-   |               ^^ help: use `||` to perform logical disjunction
+   |               ^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `||` to perform logical disjunction
+   |
+LL |     let _ = a || b;
+   |               ~~
 
 error: `or` is not a logical operator
   --> $DIR/issue-54109-without-witness.rs:26:10
    |
 LL |     if a or b {
-   |          ^^ help: use `||` to perform logical disjunction
+   |          ^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `||` to perform logical disjunction
+   |
+LL |     if a || b {
+   |          ~~
 
 error: `and` is not a logical operator
   --> $DIR/issue-54109-without-witness.rs:34:11
    |
 LL |     if (a and b) {
-   |           ^^^ help: use `&&` to perform logical conjunction
+   |           ^^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `&&` to perform logical conjunction
+   |
+LL |     if (a && b) {
+   |           ~~
 
 error: `or` is not a logical operator
   --> $DIR/issue-54109-without-witness.rs:42:11
    |
 LL |     if (a or b) {
-   |           ^^ help: use `||` to perform logical disjunction
+   |           ^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `||` to perform logical disjunction
+   |
+LL |     if (a || b) {
+   |           ~~
 
 error: `and` is not a logical operator
   --> $DIR/issue-54109-without-witness.rs:50:13
    |
 LL |     while a and b {
-   |             ^^^ help: use `&&` to perform logical conjunction
+   |             ^^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `&&` to perform logical conjunction
+   |
+LL |     while a && b {
+   |             ~~
 
 error: `or` is not a logical operator
   --> $DIR/issue-54109-without-witness.rs:58:13
    |
 LL |     while a or b {
-   |             ^^ help: use `||` to perform logical disjunction
+   |             ^^
    |
    = note: unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+help: use `||` to perform logical disjunction
+   |
+LL |     while a || b {
+   |             ~~
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/did_you_mean/pub-macro-rules.stderr b/tests/ui/did_you_mean/pub-macro-rules.stderr
index ba9020460ce..fb9148748ca 100644
--- a/tests/ui/did_you_mean/pub-macro-rules.stderr
+++ b/tests/ui/did_you_mean/pub-macro-rules.stderr
@@ -2,7 +2,12 @@ error: can't qualify macro_rules invocation with `pub`
   --> $DIR/pub-macro-rules.rs:2:5
    |
 LL |     pub macro_rules! foo {
-   |     ^^^ help: try exporting the macro: `#[macro_export]`
+   |     ^^^
+   |
+help: try exporting the macro
+   |
+LL |     #[macro_export] macro_rules! foo {
+   |     ~~~~~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
index 68734cd4ccd..a33a8c776c8 100644
--- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
+++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
@@ -2,13 +2,23 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&Copy`
   --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12
    |
 LL |     let _: &Copy + 'static;
-   |            ^^^^^^^^^^^^^^^ help: try adding parentheses: `&(Copy + 'static)`
+   |            ^^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL |     let _: &(Copy + 'static);
+   |             +              +
 
 error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy`
   --> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12
    |
 LL |     let _: &'static Copy + 'static;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'static (Copy + 'static)`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL |     let _: &'static (Copy + 'static);
+   |                     +              +
 
 error[E0038]: the trait `Copy` cannot be made into an object
   --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12
diff --git a/tests/ui/did_you_mean/use_instead_of_import.stderr b/tests/ui/did_you_mean/use_instead_of_import.stderr
index 2aac8f68c5e..f8d6de8a117 100644
--- a/tests/ui/did_you_mean/use_instead_of_import.stderr
+++ b/tests/ui/did_you_mean/use_instead_of_import.stderr
@@ -2,25 +2,45 @@ error: expected item, found `import`
   --> $DIR/use_instead_of_import.rs:3:1
    |
 LL | import std::{
-   | ^^^^^^ help: items are imported using the `use` keyword
+   | ^^^^^^
+   |
+help: items are imported using the `use` keyword
+   |
+LL | use std::{
+   | ~~~
 
 error: expected item, found `require`
   --> $DIR/use_instead_of_import.rs:9:1
    |
 LL | require std::time::Duration;
-   | ^^^^^^^ help: items are imported using the `use` keyword
+   | ^^^^^^^
+   |
+help: items are imported using the `use` keyword
+   |
+LL | use std::time::Duration;
+   | ~~~
 
 error: expected item, found `include`
   --> $DIR/use_instead_of_import.rs:12:1
    |
 LL | include std::time::Instant;
-   | ^^^^^^^ help: items are imported using the `use` keyword
+   | ^^^^^^^
+   |
+help: items are imported using the `use` keyword
+   |
+LL | use std::time::Instant;
+   | ~~~
 
 error: expected item, found `using`
   --> $DIR/use_instead_of_import.rs:15:5
    |
 LL | pub using std::io;
-   |     ^^^^^ help: items are imported using the `use` keyword
+   |     ^^^^^
+   |
+help: items are imported using the `use` keyword
+   |
+LL | pub use std::io;
+   |     ~~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/enum/nested-enum.rs b/tests/ui/enum/nested-enum.rs
index 80957b8a14c..ff39fdee6bc 100644
--- a/tests/ui/enum/nested-enum.rs
+++ b/tests/ui/enum/nested-enum.rs
@@ -1,7 +1,10 @@
 enum Foo {
-    enum Bar { Baz }, //~ ERROR `enum` definition cannot be nested inside `enum`
-    struct Quux { field: u8 }, //~ ERROR `struct` definition cannot be nested inside `enum`
-    union Wibble { field: u8 }, //~ ERROR `union` definition cannot be nested inside `enum`
+    enum Bar { Baz },
+    //~^ ERROR `enum` definition cannot be nested inside `enum`
+    struct Quux { field: u8 },
+    //~^ ERROR `struct` definition cannot be nested inside `enum`
+    union Wibble { field: u8 },
+    //~^ ERROR `union` definition cannot be nested inside `enum`
     Bat,
 }
 
diff --git a/tests/ui/enum/nested-enum.stderr b/tests/ui/enum/nested-enum.stderr
index 7d6f57e88a8..78df333abb3 100644
--- a/tests/ui/enum/nested-enum.stderr
+++ b/tests/ui/enum/nested-enum.stderr
@@ -2,25 +2,34 @@ error: `enum` definition cannot be nested inside `enum`
   --> $DIR/nested-enum.rs:2:5
    |
 LL |     enum Bar { Baz },
-   |     ^^^^------------
-   |     |
-   |     help: consider creating a new `enum` definition instead of nesting
+   |     ^^^^
+   |
+help: consider creating a new `enum` definition instead of nesting
+   |
+LL -     enum Bar { Baz },
+   |
 
 error: `struct` definition cannot be nested inside `enum`
-  --> $DIR/nested-enum.rs:3:5
+  --> $DIR/nested-enum.rs:4:5
    |
 LL |     struct Quux { field: u8 },
-   |     ^^^^^^-------------------
-   |     |
-   |     help: consider creating a new `struct` definition instead of nesting
+   |     ^^^^^^
+   |
+help: consider creating a new `struct` definition instead of nesting
+   |
+LL -     struct Quux { field: u8 },
+   |
 
 error: `union` definition cannot be nested inside `enum`
-  --> $DIR/nested-enum.rs:4:5
+  --> $DIR/nested-enum.rs:6:5
    |
 LL |     union Wibble { field: u8 },
-   |     ^^^^^---------------------
-   |     |
-   |     help: consider creating a new `union` definition instead of nesting
+   |     ^^^^^
+   |
+help: consider creating a new `union` definition instead of nesting
+   |
+LL -     union Wibble { field: u8 },
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/error-codes/E0435.stderr b/tests/ui/error-codes/E0435.stderr
index 68d6ddba2a1..1ebb9976394 100644
--- a/tests/ui/error-codes/E0435.stderr
+++ b/tests/ui/error-codes/E0435.stderr
@@ -1,10 +1,13 @@
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/E0435.rs:5:17
    |
-LL |     let foo: usize = 42;
-   |     ------- help: consider using `const` instead of `let`: `const foo`
 LL |     let _: [u8; foo];
    |                 ^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const foo: usize = 42;
+   |     ~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0586.stderr b/tests/ui/error-codes/E0586.stderr
index f562e358cba..b3e07220d3d 100644
--- a/tests/ui/error-codes/E0586.stderr
+++ b/tests/ui/error-codes/E0586.stderr
@@ -2,9 +2,14 @@ error[E0586]: inclusive range with no end
   --> $DIR/E0586.rs:3:19
    |
 LL |     let x = &tmp[1..=];
-   |                   ^^^ help: use `..` instead
+   |                   ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     let x = &tmp[1..=];
+LL +     let x = &tmp[1..];
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/expr/if/attrs/else-attrs.stderr b/tests/ui/expr/if/attrs/else-attrs.stderr
index 2733377054d..c4e51406d57 100644
--- a/tests/ui/expr/if/attrs/else-attrs.stderr
+++ b/tests/ui/expr/if/attrs/else-attrs.stderr
@@ -9,12 +9,17 @@ error: outer attributes are not allowed on `if` and `else` branches
    |
 LL |       } else #[attr] if false {
    |  _______----_^^^^^^^_-
-   | |       |    |
-   | |       |    help: remove the attributes
+   | |       |
    | |       the branch belongs to this `else`
 LL | |     } else {
 LL | |     }
    | |_____- the attributes are attached to this branch
+   |
+help: remove the attributes
+   |
+LL -     } else #[attr] if false {
+LL +     } else if false {
+   |
 
 error: expected expression, found keyword `else`
   --> $DIR/else-attrs.rs:20:15
diff --git a/tests/ui/extern/extern-const.stderr b/tests/ui/extern/extern-const.stderr
index 31954ca2c84..441495866cd 100644
--- a/tests/ui/extern/extern-const.stderr
+++ b/tests/ui/extern/extern-const.stderr
@@ -2,11 +2,13 @@ error: extern items cannot be `const`
   --> $DIR/extern-const.rs:14:11
    |
 LL |     const rust_dbg_static_mut: c_int;
-   |     ------^^^^^^^^^^^^^^^^^^^
-   |     |
-   |     help: try using a static value: `static`
+   |           ^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+help: try using a static value
+   |
+LL |     static rust_dbg_static_mut: c_int;
+   |     ~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-wasm_abi.rs b/tests/ui/feature-gates/feature-gate-wasm_abi.rs
deleted file mode 100644
index da1d9300a2b..00000000000
--- a/tests/ui/feature-gates/feature-gate-wasm_abi.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//@ needs-llvm-components: webassembly
-//@ compile-flags: --target=wasm32-unknown-unknown --crate-type=rlib
-#![no_core]
-#![feature(no_core, lang_items)]
-#[lang="sized"]
-trait Sized { }
-
-extern "wasm" fn fu() {} //~ ERROR wasm ABI is experimental
-
-trait T {
-    extern "wasm" fn mu(); //~ ERROR wasm ABI is experimental
-    extern "wasm" fn dmu() {} //~ ERROR wasm ABI is experimental
-}
-
-struct S;
-impl T for S {
-    extern "wasm" fn mu() {} //~ ERROR wasm ABI is experimental
-}
-
-impl S {
-    extern "wasm" fn imu() {} //~ ERROR wasm ABI is experimental
-}
-
-type TAU = extern "wasm" fn(); //~ ERROR wasm ABI is experimental
-
-extern "wasm" {} //~ ERROR wasm ABI is experimental
diff --git a/tests/ui/feature-gates/feature-gate-wasm_abi.stderr b/tests/ui/feature-gates/feature-gate-wasm_abi.stderr
deleted file mode 100644
index 973c42af19c..00000000000
--- a/tests/ui/feature-gates/feature-gate-wasm_abi.stderr
+++ /dev/null
@@ -1,73 +0,0 @@
-error[E0658]: wasm ABI is experimental and subject to change
-  --> $DIR/feature-gate-wasm_abi.rs:8:8
-   |
-LL | extern "wasm" fn fu() {}
-   |        ^^^^^^
-   |
-   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
-   = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change
-  --> $DIR/feature-gate-wasm_abi.rs:11:12
-   |
-LL |     extern "wasm" fn mu();
-   |            ^^^^^^
-   |
-   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
-   = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change
-  --> $DIR/feature-gate-wasm_abi.rs:12:12
-   |
-LL |     extern "wasm" fn dmu() {}
-   |            ^^^^^^
-   |
-   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
-   = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change
-  --> $DIR/feature-gate-wasm_abi.rs:17:12
-   |
-LL |     extern "wasm" fn mu() {}
-   |            ^^^^^^
-   |
-   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
-   = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change
-  --> $DIR/feature-gate-wasm_abi.rs:21:12
-   |
-LL |     extern "wasm" fn imu() {}
-   |            ^^^^^^
-   |
-   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
-   = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change
-  --> $DIR/feature-gate-wasm_abi.rs:24:19
-   |
-LL | type TAU = extern "wasm" fn();
-   |                   ^^^^^^
-   |
-   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
-   = help: add `#![feature(wasm_abi)]` 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]: wasm ABI is experimental and subject to change
-  --> $DIR/feature-gate-wasm_abi.rs:26:8
-   |
-LL | extern "wasm" {}
-   |        ^^^^^^
-   |
-   = note: see issue #83788 <https://github.com/rust-lang/rust/issues/83788> for more information
-   = help: add `#![feature(wasm_abi)]` 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 7 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs
new file mode 100644
index 00000000000..ecbfc0bce5c
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.rs
@@ -0,0 +1,6 @@
+//@ only-x86_64
+#[target_feature(enable = "amx-tile")]
+//~^ ERROR: currently unstable
+unsafe fn foo() {}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr
new file mode 100644
index 00000000000..58d577a3790
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-x86_amx_intrinsics.stderr
@@ -0,0 +1,13 @@
+error[E0658]: the target feature `amx-tile` is currently unstable
+  --> $DIR/feature-gate-x86_amx_intrinsics.rs:2:18
+   |
+LL | #[target_feature(enable = "amx-tile")]
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #126622 <https://github.com/rust-lang/rust/issues/126622> for more information
+   = help: add `#![feature(x86_amx_intrinsics)]` 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-xop_target_feature.rs b/tests/ui/feature-gates/feature-gate-xop_target_feature.rs
new file mode 100644
index 00000000000..3032a6fbb47
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-xop_target_feature.rs
@@ -0,0 +1,6 @@
+//@ only-x86_64
+#[target_feature(enable = "xop")]
+//~^ ERROR: currently unstable
+unsafe fn foo() {}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr b/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr
new file mode 100644
index 00000000000..58f7b0b3b00
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-xop_target_feature.stderr
@@ -0,0 +1,13 @@
+error[E0658]: the target feature `xop` is currently unstable
+  --> $DIR/feature-gate-xop_target_feature.rs:2:18
+   |
+LL | #[target_feature(enable = "xop")]
+   |                  ^^^^^^^^^^^^^^
+   |
+   = note: see issue #127208 <https://github.com/rust-lang/rust/issues/127208> for more information
+   = help: add `#![feature(xop_target_feature)]` 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/fmt/format-string-error-2.stderr b/tests/ui/fmt/format-string-error-2.stderr
index dfd24bf60ad..d5fe4081ac8 100644
--- a/tests/ui/fmt/format-string-error-2.stderr
+++ b/tests/ui/fmt/format-string-error-2.stderr
@@ -2,7 +2,12 @@ error: incorrect unicode escape sequence
   --> $DIR/format-string-error-2.rs:77:20
    |
 LL |     println!("\x7B}\u8 {", 1);
-   |                    ^^^ help: format of unicode escape sequences uses braces: `\u{8}`
+   |                    ^^^
+   |
+help: format of unicode escape sequences uses braces
+   |
+LL |     println!("\x7B}\u{8} {", 1);
+   |                    ~~~~~
 
 error: invalid format string: expected `'}'`, found `'a'`
   --> $DIR/format-string-error-2.rs:5:5
diff --git a/tests/ui/fn/fn-recover-return-sign.fixed b/tests/ui/fn/fn-recover-return-sign.fixed
index 20dca91fdf4..1da10a6d8fe 100644
--- a/tests/ui/fn/fn-recover-return-sign.fixed
+++ b/tests/ui/fn/fn-recover-return-sign.fixed
@@ -3,7 +3,7 @@
 fn a() -> usize { 0 }
 //~^ ERROR return types are denoted using `->`
 
-fn b()-> usize { 0 }
+fn b() -> usize { 0 }
 //~^ ERROR return types are denoted using `->`
 
 fn bar(_: u32) {}
@@ -22,7 +22,7 @@ fn main() {
     //~^ ERROR return types are denoted using `->`
     dbg!(foo(false));
 
-    let bar = |a: bool|-> bool { a };
+    let bar = |a: bool| -> bool { a };
     //~^ ERROR return types are denoted using `->`
     dbg!(bar(false));
 }
diff --git a/tests/ui/fn/fn-recover-return-sign.stderr b/tests/ui/fn/fn-recover-return-sign.stderr
index 983109730ff..e6012f3f950 100644
--- a/tests/ui/fn/fn-recover-return-sign.stderr
+++ b/tests/ui/fn/fn-recover-return-sign.stderr
@@ -2,25 +2,45 @@ error: return types are denoted using `->`
   --> $DIR/fn-recover-return-sign.rs:3:8
    |
 LL | fn a() => usize { 0 }
-   |        ^^ help: use `->` instead
+   |        ^^
+   |
+help: use `->` instead
+   |
+LL | fn a() -> usize { 0 }
+   |        ~~
 
 error: return types are denoted using `->`
   --> $DIR/fn-recover-return-sign.rs:6:7
    |
 LL | fn b(): usize { 0 }
-   |       ^ help: use `->` instead
+   |       ^
+   |
+help: use `->` instead
+   |
+LL | fn b() -> usize { 0 }
+   |        ~~
 
 error: return types are denoted using `->`
   --> $DIR/fn-recover-return-sign.rs:21:25
    |
 LL |     let foo = |a: bool| => bool { a };
-   |                         ^^ help: use `->` instead
+   |                         ^^
+   |
+help: use `->` instead
+   |
+LL |     let foo = |a: bool| -> bool { a };
+   |                         ~~
 
 error: return types are denoted using `->`
   --> $DIR/fn-recover-return-sign.rs:25:24
    |
 LL |     let bar = |a: bool|: bool { a };
-   |                        ^ help: use `->` instead
+   |                        ^
+   |
+help: use `->` instead
+   |
+LL |     let bar = |a: bool| -> bool { a };
+   |                         ~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/fn/fn-recover-return-sign2.stderr b/tests/ui/fn/fn-recover-return-sign2.stderr
index 25ee8dd0c5d..fb88ff7b950 100644
--- a/tests/ui/fn/fn-recover-return-sign2.stderr
+++ b/tests/ui/fn/fn-recover-return-sign2.stderr
@@ -2,7 +2,12 @@ error: return types are denoted using `->`
   --> $DIR/fn-recover-return-sign2.rs:4:10
    |
 LL | fn foo() => impl Fn() => bool {
-   |          ^^ help: use `->` instead
+   |          ^^
+   |
+help: use `->` instead
+   |
+LL | fn foo() -> impl Fn() => bool {
+   |          ~~
 
 error: expected one of `+`, `->`, `::`, `where`, or `{`, found `=>`
   --> $DIR/fn-recover-return-sign2.rs:4:23
diff --git a/tests/ui/generics/issue-95208-ignore-qself.stderr b/tests/ui/generics/issue-95208-ignore-qself.stderr
index cf40e857d42..7d91fbc14a1 100644
--- a/tests/ui/generics/issue-95208-ignore-qself.stderr
+++ b/tests/ui/generics/issue-95208-ignore-qself.stderr
@@ -2,9 +2,12 @@ error: expected `:` followed by trait or lifetime
   --> $DIR/issue-95208-ignore-qself.rs:6:88
    |
 LL | impl<T: Iterator> Struct<T> where <T as std:: iter::Iterator>::Item:: std::fmt::Display {
-   |                                                                    ---                 ^
-   |                                                                    |
-   |                                                                    help: use single colon: `:`
+   |                                                                                        ^
+   |
+help: use single colon
+   |
+LL | impl<T: Iterator> Struct<T> where <T as std:: iter::Iterator>::Item: std::fmt::Display {
+   |                                                                    ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generics/issue-95208.stderr b/tests/ui/generics/issue-95208.stderr
index 0d856d096af..e047f1265e2 100644
--- a/tests/ui/generics/issue-95208.stderr
+++ b/tests/ui/generics/issue-95208.stderr
@@ -2,9 +2,12 @@ error: expected `:` followed by trait or lifetime
   --> $DIR/issue-95208.rs:6:46
    |
 LL | impl<T> Struct<T> where T:: std::fmt::Display {
-   |                          ---                 ^
-   |                          |
-   |                          help: use single colon: `:`
+   |                                              ^
+   |
+help: use single colon
+   |
+LL | impl<T> Struct<T> where T: std::fmt::Display {
+   |                          ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr
index d61562bb199..4e695b2dcd6 100644
--- a/tests/ui/generics/single-colon-path-not-const-generics.stderr
+++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr
@@ -4,9 +4,13 @@ error: path separator must be a double colon
 LL | pub struct Foo {
    |            --- while parsing this struct
 LL |   a: Vec<foo::bar:A>,
-   |                  ^ help: use a double colon instead: `::`
+   |                  ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a double colon instead
+   |
+LL |   a: Vec<foo::bar::A>,
+   |                  +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
index 0d2aae689f0..0f60cd397b9 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
@@ -2,36 +2,60 @@ error: range-to patterns with `...` are not allowed
   --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:15:9
    |
 LL |         ...X => {}
-   |         ^^^ help: use `..=` instead
+   |         ^^^
+   |
+help: use `..=` instead
+   |
+LL |         ..=X => {}
+   |         ~~~
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:16:9
    |
 LL |         ...0 => {}
-   |         ^^^ help: use `..=` instead
+   |         ^^^
+   |
+help: use `..=` instead
+   |
+LL |         ..=0 => {}
+   |         ~~~
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:17:9
    |
 LL |         ...'a' => {}
-   |         ^^^ help: use `..=` instead
+   |         ^^^
+   |
+help: use `..=` instead
+   |
+LL |         ..='a' => {}
+   |         ~~~
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:18:9
    |
 LL |         ...0.0f32 => {}
-   |         ^^^ help: use `..=` instead
+   |         ^^^
+   |
+help: use `..=` instead
+   |
+LL |         ..=0.0f32 => {}
+   |         ~~~
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:25:17
    |
 LL |             let ...$e;
-   |                 ^^^ help: use `..=` instead
+   |                 ^^^
 ...
 LL |     mac!(0);
    |     ------- in this macro invocation
    |
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `..=` instead
+   |
+LL |             let ..=$e;
+   |                 ~~~
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:25:17
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
index 9ba0e09e154..204ee373bc5 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
@@ -2,57 +2,87 @@ error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:8:13
    |
 LL |     if let 0... = 1 {}
-   |             ^^^ help: use `..` instead
+   |             ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let 0... = 1 {}
+LL +     if let 0.. = 1 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:9:13
    |
 LL |     if let 0..= = 1 {}
-   |             ^^^ help: use `..` instead
+   |             ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let 0..= = 1 {}
+LL +     if let 0.. = 1 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:11:13
    |
 LL |     if let X... = 1 {}
-   |             ^^^ help: use `..` instead
+   |             ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let X... = 1 {}
+LL +     if let X.. = 1 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:12:13
    |
 LL |     if let X..= = 1 {}
-   |             ^^^ help: use `..` instead
+   |             ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let X..= = 1 {}
+LL +     if let X.. = 1 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:18:19
    |
 LL |             let $e...;
-   |                   ^^^ help: use `..` instead
+   |                   ^^^
 ...
 LL |     mac!(0);
    |     ------- in this macro invocation
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `..` instead
+   |
+LL -             let $e...;
+LL +             let $e..;
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:20:19
    |
 LL |             let $e..=;
-   |                   ^^^ help: use `..` instead
+   |                   ^^^
 ...
 LL |     mac!(0);
    |     ------- in this macro invocation
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `..` instead
+   |
+LL -             let $e..=;
+LL +             let $e..;
+   |
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/half-open-range-pats-inclusive-no-end.rs:18:17
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
index 111e8179962..83a374c3d65 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
@@ -2,53 +2,93 @@ error: the range pattern here has ambiguous interpretation
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:6:10
    |
 LL |         &0.. | _ => {}
-   |          ^^^ help: add parentheses to clarify the precedence: `(0..)`
+   |          ^^^
+   |
+help: add parentheses to clarify the precedence
+   |
+LL |         &(0..) | _ => {}
+   |          +   +
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:11
    |
 LL |         &0..= | _ => {}
-   |           ^^^ help: use `..` instead
+   |           ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -         &0..= | _ => {}
+LL +         &0.. | _ => {}
+   |
 
 error: the range pattern here has ambiguous interpretation
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:10
    |
 LL |         &0..= | _ => {}
-   |          ^^^^ help: add parentheses to clarify the precedence: `(0..=)`
+   |          ^^^^
+   |
+help: add parentheses to clarify the precedence
+   |
+LL |         &(0..=) | _ => {}
+   |          +    +
 
 error[E0586]: inclusive range with no end
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:11:11
    |
 LL |         &0... | _ => {}
-   |           ^^^ help: use `..` instead
+   |           ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -         &0... | _ => {}
+LL +         &0.. | _ => {}
+   |
 
 error: the range pattern here has ambiguous interpretation
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:16:10
    |
 LL |         &..0 | _ => {}
-   |          ^^^ help: add parentheses to clarify the precedence: `(..0)`
+   |          ^^^
+   |
+help: add parentheses to clarify the precedence
+   |
+LL |         &(..0) | _ => {}
+   |          +   +
 
 error: the range pattern here has ambiguous interpretation
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:18:10
    |
 LL |         &..=0 | _ => {}
-   |          ^^^^ help: add parentheses to clarify the precedence: `(..=0)`
+   |          ^^^^
+   |
+help: add parentheses to clarify the precedence
+   |
+LL |         &(..=0) | _ => {}
+   |          +    +
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10
    |
 LL |         &...0 | _ => {}
-   |          ^^^ help: use `..=` instead
+   |          ^^^
+   |
+help: use `..=` instead
+   |
+LL |         &..=0 | _ => {}
+   |          ~~~
 
 error: the range pattern here has ambiguous interpretation
   --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10
    |
 LL |         &...0 | _ => {}
-   |          ^^^^ help: add parentheses to clarify the precedence: `(..=0)`
+   |          ^^^^
+   |
+help: add parentheses to clarify the precedence
+   |
+LL |         &(...0) | _ => {}
+   |          +    +
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr
index e0955faac7c..94b6ffdd912 100644
--- a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr
+++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr
@@ -2,13 +2,23 @@ error: ambiguous `+` in a type
   --> $DIR/impl-fn-parsing-ambiguities.rs:4:27
    |
 LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
-   |                           ^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + '_)`
+   |                           ^^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
+   |                           +               +
 
 error: ambiguous `+` in a type
   --> $DIR/impl-fn-parsing-ambiguities.rs:10:24
    |
 LL | fn b() -> impl Fn() -> impl Debug + Send {
-   |                        ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)`
+   |                        ^^^^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | fn b() -> impl Fn() -> (impl Debug + Send) {
+   |                        +                 +
 
 error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
   --> $DIR/impl-fn-parsing-ambiguities.rs:4:40
diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.stderr b/tests/ui/impl-trait/impl-trait-plus-priority.stderr
index 205d9b0b75e..03e7910095a 100644
--- a/tests/ui/impl-trait/impl-trait-plus-priority.stderr
+++ b/tests/ui/impl-trait/impl-trait-plus-priority.stderr
@@ -2,19 +2,34 @@ error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:23:18
    |
 LL | type A = fn() -> impl A +;
-   |                  ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
+   |                  ^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = fn() -> (impl A +);
+   |                  +        +
 
 error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:25:18
    |
 LL | type A = fn() -> impl A + B;
-   |                  ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
+   |                  ^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = fn() -> (impl A + B);
+   |                  +          +
 
 error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:27:18
    |
 LL | type A = fn() -> dyn A + B;
-   |                  ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
+   |                  ^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = fn() -> (dyn A + B);
+   |                  +         +
 
 error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A`
   --> $DIR/impl-trait-plus-priority.rs:29:10
@@ -26,43 +41,78 @@ error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:32:18
    |
 LL | type A = Fn() -> impl A +;
-   |                  ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
+   |                  ^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = Fn() -> (impl A +);
+   |                  +        +
 
 error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:34:18
    |
 LL | type A = Fn() -> impl A + B;
-   |                  ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
+   |                  ^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = Fn() -> (impl A + B);
+   |                  +          +
 
 error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:36:18
    |
 LL | type A = Fn() -> dyn A + B;
-   |                  ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
+   |                  ^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = Fn() -> (dyn A + B);
+   |                  +         +
 
 error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:40:11
    |
 LL | type A = &impl A +;
-   |           ^^^^^^^^ help: use parentheses to disambiguate: `(impl A)`
+   |           ^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = &(impl A +);
+   |           +        +
 
 error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:42:11
    |
 LL | type A = &impl A + B;
-   |           ^^^^^^^^^^ help: use parentheses to disambiguate: `(impl A + B)`
+   |           ^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = &(impl A + B);
+   |           +          +
 
 error: ambiguous `+` in a type
   --> $DIR/impl-trait-plus-priority.rs:44:11
    |
 LL | type A = &dyn A + B;
-   |           ^^^^^^^^^ help: use parentheses to disambiguate: `(dyn A + B)`
+   |           ^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = &(dyn A + B);
+   |           +         +
 
 error[E0178]: expected a path on the left-hand side of `+`, not `&A`
   --> $DIR/impl-trait-plus-priority.rs:46:10
    |
 LL | type A = &A + B;
-   |          ^^^^^^ help: try adding parentheses: `&(A + B)`
+   |          ^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | type A = &(A + B);
+   |           +     +
 
 error: aborting due to 11 previous errors
 
diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr
index 6544837ba83..979c0ca6d7b 100644
--- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr
+++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr
@@ -16,10 +16,10 @@ LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x }
    |                       |                 opaque type defined here
    |                       hidden type `&'a ()` captures the lifetime `'a` as defined here
    |
-help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound
+help: add `'a` to the `use<...>` bound to explicitly capture it
    |
-LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> + 'a { x }
-   |                                                            ++++
+LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<'a> { x }
+   |                                                          ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs
new file mode 100644
index 00000000000..e0b115b0ce4
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs
@@ -0,0 +1,30 @@
+#![feature(precise_capturing)]
+
+fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> {
+//~^ HELP add `'a` to the `use<...>` bound
+    x
+//~^ ERROR hidden type for
+}
+
+fn param<'a, T>(x: &'a ()) -> impl Sized + use<T> {
+//~^ HELP add `'a` to the `use<...>` bound
+    x
+//~^ ERROR hidden type for
+}
+
+fn empty<'a>(x: &'a ()) -> impl Sized + use<> {
+//~^ HELP add `'a` to the `use<...>` bound
+    x
+//~^ ERROR hidden type for
+}
+
+trait Captures<'a> {}
+impl<T> Captures<'_> for T {}
+
+fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> {
+//~^ HELP add a `use<...>` bound
+    x
+//~^ ERROR hidden type for
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr
new file mode 100644
index 00000000000..391f16d012e
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr
@@ -0,0 +1,67 @@
+error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
+  --> $DIR/hidden-type-suggestion.rs:5:5
+   |
+LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> {
+   |             --                    -------------------- opaque type defined here
+   |             |
+   |             hidden type `&'a ()` captures the lifetime `'a` as defined here
+LL |
+LL |     x
+   |     ^
+   |
+help: add `'a` to the `use<...>` bound to explicitly capture it
+   |
+LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b, 'a> {
+   |                                                      ++++
+
+error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
+  --> $DIR/hidden-type-suggestion.rs:11:5
+   |
+LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use<T> {
+   |          --                   ------------------- opaque type defined here
+   |          |
+   |          hidden type `&'a ()` captures the lifetime `'a` as defined here
+LL |
+LL |     x
+   |     ^
+   |
+help: add `'a` to the `use<...>` bound to explicitly capture it
+   |
+LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use<'a, T> {
+   |                                                +++
+
+error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
+  --> $DIR/hidden-type-suggestion.rs:17:5
+   |
+LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<> {
+   |          --                ------------------ opaque type defined here
+   |          |
+   |          hidden type `&'a ()` captures the lifetime `'a` as defined here
+LL |
+LL |     x
+   |     ^
+   |
+help: add `'a` to the `use<...>` bound to explicitly capture it
+   |
+LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<'a> {
+   |                                             ++
+
+error[E0700]: hidden type for `impl Captures<'captured>` captures lifetime that does not appear in bounds
+  --> $DIR/hidden-type-suggestion.rs:26:5
+   |
+LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> {
+   |            --                                                    ------------------------ opaque type defined here
+   |            |
+   |            hidden type `&'a ()` captures the lifetime `'a` as defined here
+LL |
+LL |     x
+   |     ^
+   |
+help: add a `use<...>` bound to explicitly capture `'a`
+   |
+LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> + use<'captured, 'a, Captured> {
+   |                                                                                           ++++++++++++++++++++++++++++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/implied-bounds/dyn-erasure-no-tait.rs b/tests/ui/implied-bounds/dyn-erasure-no-tait.rs
new file mode 100644
index 00000000000..b5a8f421d3d
--- /dev/null
+++ b/tests/ui/implied-bounds/dyn-erasure-no-tait.rs
@@ -0,0 +1,53 @@
+//@ known-bug: #112905
+//@ check-pass
+
+// Classified as an issue with implied bounds:
+// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998
+
+/// Note: this is sound! It's the "type witness" pattern (here, lt witness).
+mod some_lib {
+    use super::T;
+
+    /// Invariant in `'a` and `'b` for soundness.
+    pub struct LtEq<'a, 'b>(::std::marker::PhantomData<*mut Self>);
+
+    impl<'a, 'b> LtEq<'a, 'b> {
+        pub fn new() -> LtEq<'a, 'a> {
+            LtEq(<_>::default())
+        }
+
+        pub fn eq(&self) -> impl 'static + Fn(T<'a>) -> T<'b> {
+            |a| unsafe { ::std::mem::transmute::<T<'a>, T<'b>>(a) }
+        }
+    }
+}
+
+use some_lib::LtEq;
+use std::{any::Any, cell::Cell};
+
+/// Feel free to choose whatever you want, here.
+type T<'lt> = Cell<&'lt str>;
+
+fn exploit<'a, 'b>(a: T<'a>) -> T<'b> {
+    let f = LtEq::<'a, 'a>::new().eq();
+    let any = Box::new(f) as Box<dyn Any>;
+
+    let new_f = None.map(LtEq::<'a, 'b>::eq);
+
+    fn downcast_a_to_type_of_new_f<F: 'static>(any: Box<dyn Any>, _: Option<F>) -> F {
+        *any.downcast().unwrap_or_else(|_| unreachable!())
+    }
+
+    let f = downcast_a_to_type_of_new_f(any, new_f);
+
+    f(a)
+}
+
+fn main() {
+    let r: T<'static> = {
+        let local = String::from("…");
+        let a: T<'_> = Cell::new(&local[..]);
+        exploit(a)
+    };
+    dbg!(r.get());
+}
diff --git a/tests/ui/implied-bounds/dyn-erasure-tait.rs b/tests/ui/implied-bounds/dyn-erasure-tait.rs
new file mode 100644
index 00000000000..4766d221d67
--- /dev/null
+++ b/tests/ui/implied-bounds/dyn-erasure-tait.rs
@@ -0,0 +1,39 @@
+//@ known-bug: #112905
+//@ check-pass
+
+// Classified as an issue with implied bounds:
+// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998
+
+#![forbid(unsafe_code)] // No `unsafe!`
+#![feature(type_alias_impl_trait)]
+
+use std::any::Any;
+
+/// Anything covariant will do, for this demo.
+type T<'lt> = &'lt str;
+
+type F<'a, 'b> = impl 'static + Fn(T<'a>) -> T<'b>;
+
+fn helper<'a, 'b>(_: [&'b &'a (); 0]) -> F<'a, 'b> {
+    |x: T<'a>| -> T<'b> { x } // this should *not* be `: 'static`
+}
+
+fn exploit<'a, 'b>(a: T<'a>) -> T<'b> {
+    let f: F<'a, 'a> = helper([]);
+    let any = Box::new(f) as Box<dyn Any>;
+
+    let f: F<'a, 'static> = *any.downcast().unwrap_or_else(|_| unreachable!());
+
+    f(a)
+}
+
+fn main() {
+    let r: T<'static> = {
+        let local = String::from("...");
+        exploit(&local)
+    };
+    // Since `r` now dangles, we can easily make the use-after-free
+    // point to newly allocated memory!
+    let _unrelated = String::from("UAF");
+    dbg!(r); // may print `UAF`! Run with `miri` to see the UB.
+}
diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr b/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr
new file mode 100644
index 00000000000..24574c8796b
--- /dev/null
+++ b/tests/ui/imports/suggest-import-ice-issue-127302.edition2015.stderr
@@ -0,0 +1,41 @@
+error[E0583]: file not found for module `config`
+  --> $DIR/suggest-import-ice-issue-127302.rs:3:1
+   |
+LL | mod config;
+   | ^^^^^^^^^^^
+   |
+   = help: to create the module `config`, create file "$DIR/config.rs" or "$DIR/config/mod.rs"
+   = note: if there is a `mod config` elsewhere in the crate already, import it with `use crate::...` instead
+
+error: format argument must be a string literal
+  --> $DIR/suggest-import-ice-issue-127302.rs:10:14
+   |
+LL |     println!(args.ctx.compiler.display());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     println!("{}", args.ctx.compiler.display());
+   |              +++++
+
+error[E0425]: cannot find value `args` in this scope
+  --> $DIR/suggest-import-ice-issue-127302.rs:6:12
+   |
+LL |     match &args.cmd {
+   |            ^^^^ not found in this scope
+   |
+help: consider importing this function
+   |
+LL + use std::env::args;
+   |
+
+error[E0532]: expected unit struct, unit variant or constant, found module `crate::config`
+  --> $DIR/suggest-import-ice-issue-127302.rs:7:9
+   |
+LL |         crate::config => {}
+   |         ^^^^^^^^^^^^^ not a unit struct, unit variant or constant
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0425, E0532, E0583.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr b/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr
new file mode 100644
index 00000000000..24574c8796b
--- /dev/null
+++ b/tests/ui/imports/suggest-import-ice-issue-127302.edition2021.stderr
@@ -0,0 +1,41 @@
+error[E0583]: file not found for module `config`
+  --> $DIR/suggest-import-ice-issue-127302.rs:3:1
+   |
+LL | mod config;
+   | ^^^^^^^^^^^
+   |
+   = help: to create the module `config`, create file "$DIR/config.rs" or "$DIR/config/mod.rs"
+   = note: if there is a `mod config` elsewhere in the crate already, import it with `use crate::...` instead
+
+error: format argument must be a string literal
+  --> $DIR/suggest-import-ice-issue-127302.rs:10:14
+   |
+LL |     println!(args.ctx.compiler.display());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     println!("{}", args.ctx.compiler.display());
+   |              +++++
+
+error[E0425]: cannot find value `args` in this scope
+  --> $DIR/suggest-import-ice-issue-127302.rs:6:12
+   |
+LL |     match &args.cmd {
+   |            ^^^^ not found in this scope
+   |
+help: consider importing this function
+   |
+LL + use std::env::args;
+   |
+
+error[E0532]: expected unit struct, unit variant or constant, found module `crate::config`
+  --> $DIR/suggest-import-ice-issue-127302.rs:7:9
+   |
+LL |         crate::config => {}
+   |         ^^^^^^^^^^^^^ not a unit struct, unit variant or constant
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0425, E0532, E0583.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/imports/suggest-import-ice-issue-127302.rs b/tests/ui/imports/suggest-import-ice-issue-127302.rs
new file mode 100644
index 00000000000..6b8d4c71831
--- /dev/null
+++ b/tests/ui/imports/suggest-import-ice-issue-127302.rs
@@ -0,0 +1,12 @@
+//@ revisions: edition2015 edition2021
+
+mod config; //~ ERROR file not found for module
+
+fn main() {
+    match &args.cmd { //~ ERROR cannot find value `args` in this scope
+        crate::config => {} //~ ERROR expected unit struct, unit variant or constant, found module `crate::config`
+    }
+
+    println!(args.ctx.compiler.display());
+    //~^ ERROR format argument must be a string literal
+}
diff --git a/tests/ui/imports/suggest-import-issue-120074.stderr b/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr
index c1dff93bbdb..414eeee0fed 100644
--- a/tests/ui/imports/suggest-import-issue-120074.stderr
+++ b/tests/ui/imports/suggest-import-issue-120074.edition2015.stderr
@@ -1,5 +1,5 @@
 error[E0433]: failed to resolve: unresolved import
-  --> $DIR/suggest-import-issue-120074.rs:10:35
+  --> $DIR/suggest-import-issue-120074.rs:12:35
    |
 LL |     println!("Hello, {}!", crate::bar::do_the_thing);
    |                                   ^^^ unresolved import
diff --git a/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr b/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr
new file mode 100644
index 00000000000..414eeee0fed
--- /dev/null
+++ b/tests/ui/imports/suggest-import-issue-120074.edition2021.stderr
@@ -0,0 +1,23 @@
+error[E0433]: failed to resolve: unresolved import
+  --> $DIR/suggest-import-issue-120074.rs:12:35
+   |
+LL |     println!("Hello, {}!", crate::bar::do_the_thing);
+   |                                   ^^^ unresolved import
+   |
+help: a similar path exists
+   |
+LL |     println!("Hello, {}!", crate::foo::bar::do_the_thing);
+   |                                   ~~~~~~~~
+help: consider importing this module
+   |
+LL + use foo::bar;
+   |
+help: if you import `bar`, refer to it directly
+   |
+LL -     println!("Hello, {}!", crate::bar::do_the_thing);
+LL +     println!("Hello, {}!", bar::do_the_thing);
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/imports/suggest-import-issue-120074.rs b/tests/ui/imports/suggest-import-issue-120074.rs
index a798e9eeeb8..7b6b5c73103 100644
--- a/tests/ui/imports/suggest-import-issue-120074.rs
+++ b/tests/ui/imports/suggest-import-issue-120074.rs
@@ -1,3 +1,5 @@
+//@ revisions: edition2015 edition2021
+
 pub mod foo {
     pub mod bar {
         pub fn do_the_thing() -> usize {
diff --git a/tests/ui/issues/issue-22638.rs b/tests/ui/issues/issue-22638.rs
index 3e401e99fb4..be9304e5829 100644
--- a/tests/ui/issues/issue-22638.rs
+++ b/tests/ui/issues/issue-22638.rs
@@ -40,7 +40,6 @@ impl C {
     pub fn matches<F: Fn()>(&self, f: &F) {
         let &C(ref base) = self;
         base.matches(&|| {
-            //~^ ERROR reached the type-length limit
             C(base.clone()).matches(f)
         })
     }
@@ -53,6 +52,7 @@ impl D {
     pub fn matches<F: Fn()>(&self, f: &F) {
         let &D(ref a) = self;
         a.matches(f)
+        //~^ ERROR reached the recursion limit while instantiating
     }
 }
 
diff --git a/tests/ui/issues/issue-22638.stderr b/tests/ui/issues/issue-22638.stderr
index 1344409c770..96f17944868 100644
--- a/tests/ui/issues/issue-22638.stderr
+++ b/tests/ui/issues/issue-22638.stderr
@@ -1,13 +1,14 @@
-error: reached the type-length limit while instantiating `D::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>`
-  --> $DIR/issue-22638.rs:42:9
+error: reached the recursion limit while instantiating `A::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>`
+  --> $DIR/issue-22638.rs:54:9
    |
-LL | /         base.matches(&|| {
-LL | |
-LL | |             C(base.clone()).matches(f)
-LL | |         })
-   | |__________^
+LL |         a.matches(f)
+   |         ^^^^^^^^^^^^
    |
-   = help: consider adding a `#![type_length_limit="30408681"]` attribute to your crate
+note: `A::matches` defined here
+  --> $DIR/issue-22638.rs:13:5
+   |
+LL |     pub fn matches<F: Fn()>(&self, f: &F) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-27433.fixed b/tests/ui/issues/issue-27433.fixed
index ff6704e393b..f847b698976 100644
--- a/tests/ui/issues/issue-27433.fixed
+++ b/tests/ui/issues/issue-27433.fixed
@@ -3,5 +3,5 @@ fn main() {
     let foo = 42u32;
     #[allow(unused_variables, non_snake_case)]
     let FOO : u32 = foo;
-                   //~^ ERROR attempt to use a non-constant value in a constant
+    //~^ ERROR attempt to use a non-constant value in a constant
 }
diff --git a/tests/ui/issues/issue-27433.rs b/tests/ui/issues/issue-27433.rs
index 2a34b43f58d..9bbc5bcbb45 100644
--- a/tests/ui/issues/issue-27433.rs
+++ b/tests/ui/issues/issue-27433.rs
@@ -3,5 +3,5 @@ fn main() {
     let foo = 42u32;
     #[allow(unused_variables, non_snake_case)]
     const FOO : u32 = foo;
-                   //~^ ERROR attempt to use a non-constant value in a constant
+    //~^ ERROR attempt to use a non-constant value in a constant
 }
diff --git a/tests/ui/issues/issue-27433.stderr b/tests/ui/issues/issue-27433.stderr
index aba8e612858..f6d5fc2b768 100644
--- a/tests/ui/issues/issue-27433.stderr
+++ b/tests/ui/issues/issue-27433.stderr
@@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-27433.rs:5:23
    |
 LL |     const FOO : u32 = foo;
-   |     ---------         ^^^ non-constant value
-   |     |
-   |     help: consider using `let` instead of `const`: `let FOO`
+   |                       ^^^ non-constant value
+   |
+help: consider using `let` instead of `const`
+   |
+LL |     let FOO : u32 = foo;
+   |     ~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-3521-2.stderr b/tests/ui/issues/issue-3521-2.stderr
index 0be0e93c19e..a12241cb1df 100644
--- a/tests/ui/issues/issue-3521-2.stderr
+++ b/tests/ui/issues/issue-3521-2.stderr
@@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-3521-2.rs:5:23
    |
 LL |     static y: isize = foo + 1;
-   |     --------          ^^^ non-constant value
-   |     |
-   |     help: consider using `let` instead of `static`: `let y`
+   |                       ^^^ non-constant value
+   |
+help: consider using `let` instead of `static`
+   |
+LL |     let y: isize = foo + 1;
+   |     ~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr
index 3676f388891..9661dbf2f62 100644
--- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr
+++ b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.stderr
@@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-3668-2.rs:4:27
    |
 LL |     static child: isize = x + 1;
-   |     ------------          ^ non-constant value
-   |     |
-   |     help: consider using `let` instead of `static`: `let child`
+   |                           ^ non-constant value
+   |
+help: consider using `let` instead of `static`
+   |
+LL |     let child: isize = x + 1;
+   |     ~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr
index d761b2d87db..7fad45f4b1a 100644
--- a/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr
+++ b/tests/ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.stderr
@@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-3668.rs:8:34
    |
 LL |        static childVal: Box<P> = self.child.get();
-   |        ---------------           ^^^^ non-constant value
-   |        |
-   |        help: consider using `let` instead of `static`: `let childVal`
+   |                                  ^^^^ non-constant value
+   |
+help: consider using `let` instead of `static`
+   |
+LL |        let childVal: Box<P> = self.child.get();
+   |        ~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs
index 131c7535537..96e2691164b 100644
--- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs
+++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs
@@ -15,7 +15,7 @@ impl<T> Foo for T {
     #[allow(unconditional_recursion)]
     fn recurse(&self) {
         (self, self).recurse();
-        //~^ ERROR reached the type-length limit
+        //~^ ERROR reached the recursion limit while instantiating
     }
 }
 
diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
index 2978ced5279..84ed97572b3 100644
--- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
+++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
@@ -1,10 +1,14 @@
-error: reached the type-length limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse`
+error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse`
   --> $DIR/issue-37311.rs:17:9
    |
 LL |         (self, self).recurse();
    |         ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider adding a `#![type_length_limit="33554429"]` attribute to your crate
+note: `<T as Foo>::recurse` defined here
+  --> $DIR/issue-37311.rs:16:5
+   |
+LL |     fn recurse(&self) {
+   |     ^^^^^^^^^^^^^^^^^
    = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt'
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/issues/issue-40782.stderr b/tests/ui/issues/issue-40782.stderr
index 81f419bf687..61498020238 100644
--- a/tests/ui/issues/issue-40782.stderr
+++ b/tests/ui/issues/issue-40782.stderr
@@ -2,13 +2,23 @@ error: missing `in` in `for` loop
   --> $DIR/issue-40782.rs:4:11
    |
 LL |     for _i 0..2 {
-   |           ^ help: try adding `in` here
+   |           ^
+   |
+help: try adding `in` here
+   |
+LL |     for _i in 0..2 {
+   |            ++
 
 error: missing `in` in `for` loop
   --> $DIR/issue-40782.rs:6:12
    |
 LL |     for _i of 0..2 {
-   |            ^^ help: try using `in` here instead
+   |            ^^
+   |
+help: try using `in` here instead
+   |
+LL |     for _i in 0..2 {
+   |            ~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-44239.stderr b/tests/ui/issues/issue-44239.stderr
index 633fb177b75..1a047d4c63b 100644
--- a/tests/ui/issues/issue-44239.stderr
+++ b/tests/ui/issues/issue-44239.stderr
@@ -1,11 +1,13 @@
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-44239.rs:8:26
    |
-LL |     let n: usize = 0;
-   |     ----- help: consider using `const` instead of `let`: `const n`
-...
 LL |         const N: usize = n;
    |                          ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const n: usize = 0;
+   |     ~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs
index 4f3ddce69d8..6730865b6c7 100644
--- a/tests/ui/iterators/issue-58952-filter-type-length.rs
+++ b/tests/ui/iterators/issue-58952-filter-type-length.rs
@@ -1,5 +1,4 @@
-//@ build-fail
-//@ error-pattern: reached the type-length limit while instantiating
+//@ build-pass
 
 //! This snippet causes the type length to blowup exponentially,
 //! so check that we don't accidentally exceed the type length limit.
diff --git a/tests/ui/iterators/issue-58952-filter-type-length.stderr b/tests/ui/iterators/issue-58952-filter-type-length.stderr
deleted file mode 100644
index 975fcd4afff..00000000000
--- a/tests/ui/iterators/issue-58952-filter-type-length.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: reached the type-length limit while instantiating `<std::vec::IntoIter<i32> as Iterator>::try_fold::<vec::in_place_drop::InPlaceDrop<i32>, {closure@iter::adapters::filter::filter_try_fold<'_, ..., ..., ..., ..., ...>::{closure#0}}, ...>`
-  --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
-   |
-   = help: consider adding a `#![type_length_limit="21233607"]` attribute to your crate
-   = note: the full type name has been written to '$TEST_BUILD_DIR/iterators/issue-58952-filter-type-length/issue-58952-filter-type-length.long-type.txt'
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/label/label_misspelled_2.stderr b/tests/ui/label/label_misspelled_2.stderr
index 960646d9894..10b0e7b4e08 100644
--- a/tests/ui/label/label_misspelled_2.stderr
+++ b/tests/ui/label/label_misspelled_2.stderr
@@ -2,13 +2,23 @@ error: malformed loop label
   --> $DIR/label_misspelled_2.rs:10:5
    |
 LL |     c: for _ in 0..1 {
-   |     ^ help: use the correct loop label format: `'c`
+   |     ^
+   |
+help: use the correct loop label format
+   |
+LL |     'c: for _ in 0..1 {
+   |     +
 
 error: malformed loop label
   --> $DIR/label_misspelled_2.rs:13:5
    |
 LL |     d: for _ in 0..1 {
-   |     ^ help: use the correct loop label format: `'d`
+   |     ^
+   |
+help: use the correct loop label format
+   |
+LL |     'd: for _ in 0..1 {
+   |     +
 
 error[E0425]: cannot find value `b` in this scope
   --> $DIR/label_misspelled_2.rs:8:15
diff --git a/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr b/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr
index 1a21fed63bd..da80991c727 100644
--- a/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr
+++ b/tests/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr
@@ -26,7 +26,12 @@ error: bare CR not allowed in string, use `\r` instead
   --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:19:18
    |
 LL |     let _s = "foo
bar";
-   |                  ^ help: escape the character: `\r`
+   |                  ^
+   |
+help: escape the character
+   |
+LL |     let _s = "foo\rbar";
+   |                  ++
 
 error: bare CR not allowed in raw string
   --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:22:19
diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs
new file mode 100644
index 00000000000..6f2ead70db8
--- /dev/null
+++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs
@@ -0,0 +1,14 @@
+#![feature(unsafe_extern_blocks)]
+#![deny(unsafe_code)]
+
+#[allow(unsafe_code)]
+unsafe extern "C" {
+    fn foo();
+}
+
+unsafe extern "C" {
+    //~^ ERROR usage of an `unsafe extern` block [unsafe_code]
+    fn bar();
+}
+
+fn main() {}
diff --git a/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr
new file mode 100644
index 00000000000..5439a311256
--- /dev/null
+++ b/tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr
@@ -0,0 +1,17 @@
+error: usage of an `unsafe extern` block
+  --> $DIR/unsafe-extern-blocks.rs:9:1
+   |
+LL | / unsafe extern "C" {
+LL | |
+LL | |     fn bar();
+LL | | }
+   | |_^
+   |
+note: the lint level is defined here
+  --> $DIR/unsafe-extern-blocks.rs:2:9
+   |
+LL | #![deny(unsafe_code)]
+   |         ^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/macros/recovery-allowed.stderr b/tests/ui/macros/recovery-allowed.stderr
index 44689853dab..825f7a8faf8 100644
--- a/tests/ui/macros/recovery-allowed.stderr
+++ b/tests/ui/macros/recovery-allowed.stderr
@@ -2,9 +2,12 @@ error: unexpected `1` after identifier
   --> $DIR/recovery-allowed.rs:5:23
    |
 LL | please_recover! { not 1 }
-   |                   ----^
-   |                   |
-   |                   help: use `!` to perform bitwise not
+   |                       ^
+   |
+help: use `!` to perform bitwise not
+   |
+LL | please_recover! { !1 }
+   |                   ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/malformed/malformed-special-attrs.stderr b/tests/ui/malformed/malformed-special-attrs.stderr
index 1764c3969cf..8f2ce20593f 100644
--- a/tests/ui/malformed/malformed-special-attrs.stderr
+++ b/tests/ui/malformed/malformed-special-attrs.stderr
@@ -2,17 +2,25 @@ error: malformed `cfg_attr` attribute input
   --> $DIR/malformed-special-attrs.rs:1:1
    |
 LL | #[cfg_attr]
-   | ^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+   | ^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+help: missing condition and attribute
+   |
+LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: malformed `cfg_attr` attribute input
   --> $DIR/malformed-special-attrs.rs:4:1
    |
 LL | #[cfg_attr = ""]
-   | ^^^^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+   | ^^^^^^^^^^^^^^^^
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+help: missing condition and attribute
+   |
+LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: malformed `derive` attribute input
   --> $DIR/malformed-special-attrs.rs:7:1
diff --git a/tests/ui/methods/filter-relevant-fn-bounds.rs b/tests/ui/methods/filter-relevant-fn-bounds.rs
new file mode 100644
index 00000000000..76ececf7baa
--- /dev/null
+++ b/tests/ui/methods/filter-relevant-fn-bounds.rs
@@ -0,0 +1,23 @@
+trait Output<'a> {
+    type Type;
+}
+
+struct Wrapper;
+
+impl Wrapper {
+    fn do_something_wrapper<O, F>(self, _: F)
+    //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
+    //~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
+    where
+        F: for<'a> FnOnce(<F as Output<'a>>::Type),
+        //~^ ERROR the trait bound `F: Output<'_>` is not satisfied
+        //~| ERROR the trait bound `F: Output<'_>` is not satisfied
+    {
+    }
+}
+
+fn main() {
+    let mut wrapper = Wrapper;
+    wrapper.do_something_wrapper(|value| ());
+    //~^ ERROR expected a `FnOnce
+}
diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr
new file mode 100644
index 00000000000..b737c0ab11f
--- /dev/null
+++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr
@@ -0,0 +1,74 @@
+error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
+  --> $DIR/filter-relevant-fn-bounds.rs:8:5
+   |
+LL | /     fn do_something_wrapper<O, F>(self, _: F)
+LL | |
+LL | |
+LL | |     where
+LL | |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
+   | |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F`
+   |
+help: consider further restricting this bound
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
+   |                                                    ++++++++++++++++++++
+
+error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
+  --> $DIR/filter-relevant-fn-bounds.rs:8:8
+   |
+LL |     fn do_something_wrapper<O, F>(self, _: F)
+   |        ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F`
+   |
+help: consider further restricting this bound
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
+   |                                                    ++++++++++++++++++++
+
+error[E0277]: the trait bound `F: Output<'_>` is not satisfied
+  --> $DIR/filter-relevant-fn-bounds.rs:12:12
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
+   |
+help: consider further restricting this bound
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
+   |                                                    ++++++++++++
+
+error[E0277]: the trait bound `F: Output<'_>` is not satisfied
+  --> $DIR/filter-relevant-fn-bounds.rs:12:20
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
+   |
+help: consider further restricting this bound
+   |
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
+   |                                                    ++++++++++++
+
+error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
+  --> $DIR/filter-relevant-fn-bounds.rs:21:34
+   |
+LL |     wrapper.do_something_wrapper(|value| ());
+   |             -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
+   |             |
+   |             required by a bound introduced by this call
+   |
+   = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
+help: this trait has no implementations, consider adding one
+  --> $DIR/filter-relevant-fn-bounds.rs:1:1
+   |
+LL | trait Output<'a> {
+   | ^^^^^^^^^^^^^^^^
+note: required by a bound in `Wrapper::do_something_wrapper`
+  --> $DIR/filter-relevant-fn-bounds.rs:12:12
+   |
+LL |     fn do_something_wrapper<O, F>(self, _: F)
+   |        -------------------- required by a bound in this associated function
+...
+LL |         F: for<'a> FnOnce(<F as Output<'a>>::Type),
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs
new file mode 100644
index 00000000000..f589e88f68e
--- /dev/null
+++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs
@@ -0,0 +1,18 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/127545>.
+#![crate_type = "lib"]
+
+pub fn foo(arg: Option<&Vec<i32>>) -> Option<&[i32]> {
+    arg //~ ERROR 5:5: 5:8: mismatched types [E0308]
+}
+
+pub fn bar(arg: Option<&Vec<i32>>) -> &[i32] {
+    arg.unwrap_or(&[]) //~ ERROR 9:19: 9:22: mismatched types [E0308]
+}
+
+pub fn barzz<'a>(arg: Option<&'a Vec<i32>>, v: &'a [i32]) -> &'a [i32] {
+    arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308]
+}
+
+pub fn convert_result(arg: Result<&Vec<i32>, ()>) -> &[i32] {
+    arg.unwrap_or(&[]) //~ ERROR 17:19: 17:22: mismatched types [E0308]
+}
diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
new file mode 100644
index 00000000000..ad423f86ef9
--- /dev/null
+++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
@@ -0,0 +1,90 @@
+error[E0308]: mismatched types
+  --> $DIR/transforming-option-ref-issue-127545.rs:5:5
+   |
+LL | pub fn foo(arg: Option<&Vec<i32>>) -> Option<&[i32]> {
+   |                                       -------------- expected `Option<&[i32]>` because of return type
+LL |     arg
+   |     ^^^ expected `Option<&[i32]>`, found `Option<&Vec<i32>>`
+   |
+   = note: expected enum `Option<&[i32]>`
+              found enum `Option<&Vec<i32>>`
+help: try using `.map(|v| &**v)` to convert `Option<&Vec<i32>>` to `Option<&[i32]>`
+   |
+LL |     arg.map(|v| &**v)
+   |        ++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/transforming-option-ref-issue-127545.rs:9:19
+   |
+LL |     arg.unwrap_or(&[])
+   |         --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
+   |         |
+   |         arguments to this method are incorrect
+   |
+   = note: expected reference `&Vec<i32>`
+              found reference `&[_; 0]`
+help: the return type of this call is `&[_; 0]` due to the type of the argument passed
+  --> $DIR/transforming-option-ref-issue-127545.rs:9:5
+   |
+LL |     arg.unwrap_or(&[])
+   |     ^^^^^^^^^^^^^^---^
+   |                   |
+   |                   this argument influences the return type of `unwrap_or`
+note: method defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+help: use `Option::map_or` to deref inner value of `Option`
+   |
+LL |     arg.map_or(&[], |v| v)
+   |         ~~~~~~    +++++++
+
+error[E0308]: mismatched types
+  --> $DIR/transforming-option-ref-issue-127545.rs:13:19
+   |
+LL |     arg.unwrap_or(v)
+   |         --------- ^ expected `&Vec<i32>`, found `&[i32]`
+   |         |
+   |         arguments to this method are incorrect
+   |
+   = note: expected reference `&Vec<i32>`
+              found reference `&'a [i32]`
+help: the return type of this call is `&'a [i32]` due to the type of the argument passed
+  --> $DIR/transforming-option-ref-issue-127545.rs:13:5
+   |
+LL |     arg.unwrap_or(v)
+   |     ^^^^^^^^^^^^^^-^
+   |                   |
+   |                   this argument influences the return type of `unwrap_or`
+note: method defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+help: use `Option::map_or` to deref inner value of `Option`
+   |
+LL |     arg.map_or(v, |v| v)
+   |         ~~~~~~  +++++++
+
+error[E0308]: mismatched types
+  --> $DIR/transforming-option-ref-issue-127545.rs:17:19
+   |
+LL |     arg.unwrap_or(&[])
+   |         --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
+   |         |
+   |         arguments to this method are incorrect
+   |
+   = note: expected reference `&Vec<i32>`
+              found reference `&[_; 0]`
+help: the return type of this call is `&[_; 0]` due to the type of the argument passed
+  --> $DIR/transforming-option-ref-issue-127545.rs:17:5
+   |
+LL |     arg.unwrap_or(&[])
+   |     ^^^^^^^^^^^^^^---^
+   |                   |
+   |                   this argument influences the return type of `unwrap_or`
+note: method defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+help: use `Result::map_or` to deref inner value of `Result`
+   |
+LL |     arg.map_or(&[], |v| v)
+   |         ~~~~~~    +++++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.fixed b/tests/ui/moves/moved-value-on-as-ref-arg.fixed
new file mode 100644
index 00000000000..292fa98a3f7
--- /dev/null
+++ b/tests/ui/moves/moved-value-on-as-ref-arg.fixed
@@ -0,0 +1,37 @@
+//@ run-rustfix
+#![allow(unused_mut)]
+use std::borrow::{Borrow, BorrowMut};
+use std::convert::{AsMut, AsRef};
+struct Bar;
+
+impl AsRef<Bar> for Bar {
+    fn as_ref(&self) -> &Bar {
+        self
+    }
+}
+
+impl AsMut<Bar> for Bar {
+    fn as_mut(&mut self) -> &mut Bar {
+        self
+    }
+}
+
+fn foo<T: AsRef<Bar>>(_: T) {}
+fn qux<T: AsMut<Bar>>(_: T) {}
+fn bat<T: Borrow<T>>(_: T) {}
+fn baz<T: BorrowMut<T>>(_: T) {}
+
+pub fn main() {
+    let bar = Bar;
+    foo(&bar);
+    let _baa = bar; //~ ERROR use of moved value
+    let mut bar = Bar;
+    qux(&mut bar);
+    let _baa = bar; //~ ERROR use of moved value
+    let bar = Bar;
+    bat(&bar);
+    let _baa = bar; //~ ERROR use of moved value
+    let mut bar = Bar;
+    baz(&mut bar);
+    let _baa = bar; //~ ERROR use of moved value
+}
diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.rs b/tests/ui/moves/moved-value-on-as-ref-arg.rs
new file mode 100644
index 00000000000..632af9efcda
--- /dev/null
+++ b/tests/ui/moves/moved-value-on-as-ref-arg.rs
@@ -0,0 +1,37 @@
+//@ run-rustfix
+#![allow(unused_mut)]
+use std::borrow::{Borrow, BorrowMut};
+use std::convert::{AsMut, AsRef};
+struct Bar;
+
+impl AsRef<Bar> for Bar {
+    fn as_ref(&self) -> &Bar {
+        self
+    }
+}
+
+impl AsMut<Bar> for Bar {
+    fn as_mut(&mut self) -> &mut Bar {
+        self
+    }
+}
+
+fn foo<T: AsRef<Bar>>(_: T) {}
+fn qux<T: AsMut<Bar>>(_: T) {}
+fn bat<T: Borrow<T>>(_: T) {}
+fn baz<T: BorrowMut<T>>(_: T) {}
+
+pub fn main() {
+    let bar = Bar;
+    foo(bar);
+    let _baa = bar; //~ ERROR use of moved value
+    let mut bar = Bar;
+    qux(bar);
+    let _baa = bar; //~ ERROR use of moved value
+    let bar = Bar;
+    bat(bar);
+    let _baa = bar; //~ ERROR use of moved value
+    let mut bar = Bar;
+    baz(bar);
+    let _baa = bar; //~ ERROR use of moved value
+}
diff --git a/tests/ui/moves/moved-value-on-as-ref-arg.stderr b/tests/ui/moves/moved-value-on-as-ref-arg.stderr
new file mode 100644
index 00000000000..4004b7a43bc
--- /dev/null
+++ b/tests/ui/moves/moved-value-on-as-ref-arg.stderr
@@ -0,0 +1,79 @@
+error[E0382]: use of moved value: `bar`
+  --> $DIR/moved-value-on-as-ref-arg.rs:27:16
+   |
+LL |     let bar = Bar;
+   |         --- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait
+LL |     foo(bar);
+   |         --- value moved here
+LL |     let _baa = bar;
+   |                ^^^ value used here after move
+   |
+help: borrow the value to avoid moving it
+   |
+LL |     foo(&bar);
+   |         +
+
+error[E0382]: use of moved value: `bar`
+  --> $DIR/moved-value-on-as-ref-arg.rs:30:16
+   |
+LL |     let mut bar = Bar;
+   |         ------- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait
+LL |     qux(bar);
+   |         --- value moved here
+LL |     let _baa = bar;
+   |                ^^^ value used here after move
+   |
+note: if `Bar` implemented `Clone`, you could clone the value
+  --> $DIR/moved-value-on-as-ref-arg.rs:5:1
+   |
+LL | struct Bar;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     qux(bar);
+   |         --- you could clone this value
+help: borrow the value to avoid moving it
+   |
+LL |     qux(&mut bar);
+   |         ++++
+
+error[E0382]: use of moved value: `bar`
+  --> $DIR/moved-value-on-as-ref-arg.rs:33:16
+   |
+LL |     let bar = Bar;
+   |         --- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait
+LL |     bat(bar);
+   |         --- value moved here
+LL |     let _baa = bar;
+   |                ^^^ value used here after move
+   |
+help: borrow the value to avoid moving it
+   |
+LL |     bat(&bar);
+   |         +
+
+error[E0382]: use of moved value: `bar`
+  --> $DIR/moved-value-on-as-ref-arg.rs:36:16
+   |
+LL |     let mut bar = Bar;
+   |         ------- move occurs because `bar` has type `Bar`, which does not implement the `Copy` trait
+LL |     baz(bar);
+   |         --- value moved here
+LL |     let _baa = bar;
+   |                ^^^ value used here after move
+   |
+note: if `Bar` implemented `Clone`, you could clone the value
+  --> $DIR/moved-value-on-as-ref-arg.rs:5:1
+   |
+LL | struct Bar;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     baz(bar);
+   |         --- you could clone this value
+help: borrow the value to avoid moving it
+   |
+LL |     baz(&mut bar);
+   |         ++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr
index 517f910080d..4ff45d7a848 100644
--- a/tests/ui/object-safety/avoid-ice-on-warning.new.stderr
+++ b/tests/ui/object-safety/avoid-ice-on-warning.new.stderr
@@ -2,7 +2,12 @@ error: return types are denoted using `->`
   --> $DIR/avoid-ice-on-warning.rs:4:23
    |
 LL | fn call_this<F>(f: F) : Fn(&str) + call_that {}
-   |                       ^ help: use `->` instead
+   |                       ^
+   |
+help: use `->` instead
+   |
+LL | fn call_this<F>(f: F) -> Fn(&str) + call_that {}
+   |                       ~~
 
 error[E0405]: cannot find trait `call_that` in this scope
   --> $DIR/avoid-ice-on-warning.rs:4:36
diff --git a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr
index 3939c06eabe..de45ec8c405 100644
--- a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr
+++ b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr
@@ -2,7 +2,12 @@ error: return types are denoted using `->`
   --> $DIR/avoid-ice-on-warning.rs:4:23
    |
 LL | fn call_this<F>(f: F) : Fn(&str) + call_that {}
-   |                       ^ help: use `->` instead
+   |                       ^
+   |
+help: use `->` instead
+   |
+LL | fn call_this<F>(f: F) -> Fn(&str) + call_that {}
+   |                       ~~
 
 error[E0405]: cannot find trait `call_that` in this scope
   --> $DIR/avoid-ice-on-warning.rs:4:36
diff --git a/tests/ui/operator-recovery/less-than-greater-than.stderr b/tests/ui/operator-recovery/less-than-greater-than.stderr
index 21b2e77db9a..36a4a81035f 100644
--- a/tests/ui/operator-recovery/less-than-greater-than.stderr
+++ b/tests/ui/operator-recovery/less-than-greater-than.stderr
@@ -2,7 +2,12 @@ error: invalid comparison operator `<>`
   --> $DIR/less-than-greater-than.rs:2:22
    |
 LL |     println!("{}", 1 <> 2);
-   |                      ^^ help: `<>` is not a valid comparison operator, use `!=`
+   |                      ^^
+   |
+help: `<>` is not a valid comparison operator, use `!=`
+   |
+LL |     println!("{}", 1 != 2);
+   |                      ~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.stderr b/tests/ui/or-patterns/fn-param-wrap-parens.stderr
index 1b9614a1378..da2832ef1ae 100644
--- a/tests/ui/or-patterns/fn-param-wrap-parens.stderr
+++ b/tests/ui/or-patterns/fn-param-wrap-parens.stderr
@@ -2,7 +2,12 @@ error: top-level or-patterns are not allowed in function parameters
   --> $DIR/fn-param-wrap-parens.rs:13:9
    |
 LL | fn fun1(A | B: E) {}
-   |         ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+   |         ^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL | fn fun1((A | B): E) {}
+   |         +     +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr
index 9b827794f5b..91db3d049f6 100644
--- a/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr
+++ b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr
@@ -4,7 +4,13 @@ error: a trailing `|` is not allowed in an or-pattern
 LL |         E::A |
    |         ---- while parsing this or-pattern starting here
 LL |         E::B |
-   |              ^ help: remove the `|`
+   |              ^
+   |
+help: remove the `|`
+   |
+LL -         E::B |
+LL +         E::B
+   |
 
 error[E0308]: mismatched types
   --> $DIR/issue-64879-trailing-before-guard.rs:12:42
diff --git a/tests/ui/or-patterns/multiple-pattern-typo.stderr b/tests/ui/or-patterns/multiple-pattern-typo.stderr
index b0a82b3673b..2e66f54979b 100644
--- a/tests/ui/or-patterns/multiple-pattern-typo.stderr
+++ b/tests/ui/or-patterns/multiple-pattern-typo.stderr
@@ -2,55 +2,90 @@ error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:7:15
    |
 LL |         1 | 2 || 3 => (),
-   |         -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         -     ^^
    |         |
    |         while parsing this or-pattern starting here
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |         1 | 2 | 3 => (),
+   |               ~
 
 error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:12:16
    |
 LL |         (1 | 2 || 3) => (),
-   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^
    |          |
    |          while parsing this or-pattern starting here
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |         (1 | 2 | 3) => (),
+   |                ~
 
 error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:17:16
    |
 LL |         (1 | 2 || 3,) => (),
-   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^
    |          |
    |          while parsing this or-pattern starting here
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |         (1 | 2 | 3,) => (),
+   |                ~
 
 error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:24:18
    |
 LL |         TS(1 | 2 || 3) => (),
-   |            -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |            -     ^^
    |            |
    |            while parsing this or-pattern starting here
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |         TS(1 | 2 | 3) => (),
+   |                  ~
 
 error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:31:23
    |
 LL |         NS { f: 1 | 2 || 3 } => (),
-   |                 -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |                 -     ^^
    |                 |
    |                 while parsing this or-pattern starting here
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |         NS { f: 1 | 2 | 3 } => (),
+   |                       ~
 
 error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:36:16
    |
 LL |         [1 | 2 || 3] => (),
-   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^
    |          |
    |          while parsing this or-pattern starting here
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |         [1 | 2 | 3] => (),
+   |                ~
 
 error: unexpected token `||` in pattern
   --> $DIR/multiple-pattern-typo.rs:41:9
    |
 LL |         || 1 | 2 | 3 => (),
-   |         ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         ^^
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |         | 1 | 2 | 3 => (),
+   |         ~
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/or-patterns/nested-undelimited-precedence.stderr b/tests/ui/or-patterns/nested-undelimited-precedence.stderr
index 5a63e621f4a..f16d83ecaea 100644
--- a/tests/ui/or-patterns/nested-undelimited-precedence.stderr
+++ b/tests/ui/or-patterns/nested-undelimited-precedence.stderr
@@ -2,31 +2,56 @@ error: top-level or-patterns are not allowed in `let` bindings
   --> $DIR/nested-undelimited-precedence.rs:19:9
    |
 LL |     let b @ A | B: E = A;
-   |         ^^^^^^^^^ help: wrap the pattern in parentheses: `(b @ A | B)`
+   |         ^^^^^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     let (b @ A | B): E = A;
+   |         +         +
 
 error: top-level or-patterns are not allowed in `let` bindings
   --> $DIR/nested-undelimited-precedence.rs:34:9
    |
 LL |     let &A(_) | B(_): F = A(3);
-   |         ^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&A(_) | B(_))`
+   |         ^^^^^^^^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     let (&A(_) | B(_)): F = A(3);
+   |         +            +
 
 error: top-level or-patterns are not allowed in `let` bindings
   --> $DIR/nested-undelimited-precedence.rs:36:9
    |
 LL |     let &&A(_) | B(_): F = A(3);
-   |         ^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&A(_) | B(_))`
+   |         ^^^^^^^^^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     let (&&A(_) | B(_)): F = A(3);
+   |         +             +
 
 error: top-level or-patterns are not allowed in `let` bindings
   --> $DIR/nested-undelimited-precedence.rs:38:9
    |
 LL |     let &mut A(_) | B(_): F = A(3);
-   |         ^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&mut A(_) | B(_))`
+   |         ^^^^^^^^^^^^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     let (&mut A(_) | B(_)): F = A(3);
+   |         +                +
 
 error: top-level or-patterns are not allowed in `let` bindings
   --> $DIR/nested-undelimited-precedence.rs:40:9
    |
 LL |     let &&mut A(_) | B(_): F = A(3);
-   |         ^^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&mut A(_) | B(_))`
+   |         ^^^^^^^^^^^^^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     let (&&mut A(_) | B(_)): F = A(3);
+   |         +                 +
 
 error[E0408]: variable `b` is not bound in all patterns
   --> $DIR/nested-undelimited-precedence.rs:19:17
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
index e09194d5d39..5608138078f 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
+++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
@@ -16,25 +16,45 @@ error: top-level or-patterns are not allowed in function parameters
   --> $DIR/or-patterns-syntactic-fail.rs:18:13
    |
 LL |     fn fun1(A | B: E) {}
-   |             ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+   |             ^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     fn fun1((A | B): E) {}
+   |             +     +
 
 error: top-level or-patterns are not allowed in function parameters
   --> $DIR/or-patterns-syntactic-fail.rs:21:13
    |
 LL |     fn fun2(| A | B: E) {}
-   |             ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+   |             ^^^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     fn fun2((| A | B): E) {}
+   |             +       +
 
 error: top-level or-patterns are not allowed in `let` bindings
   --> $DIR/or-patterns-syntactic-fail.rs:26:9
    |
 LL |     let A | B: E = A;
-   |         ^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+   |         ^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     let (A | B): E = A;
+   |         +     +
 
 error: top-level or-patterns are not allowed in `let` bindings
   --> $DIR/or-patterns-syntactic-fail.rs:29:9
    |
 LL |     let | A | B: E = A;
-   |         ^^^^^^^ help: wrap the pattern in parentheses: `(A | B)`
+   |         ^^^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     let (| A | B): E = A;
+   |         +       +
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed
index 8f7aab6a499..3ec815c8468 100644
--- a/tests/ui/or-patterns/remove-leading-vert.fixed
+++ b/tests/ui/or-patterns/remove-leading-vert.fixed
@@ -8,7 +8,7 @@ fn main() {}
 
 #[cfg(FALSE)]
 fn leading() {
-    fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed
+    fn fun1(  A: E) {} //~ ERROR top-level or-patterns are not allowed
     fn fun2(  A: E) {} //~ ERROR unexpected `||` before function parameter
     let ( | A): E;
     let ( | A): (E); //~ ERROR unexpected token `||` in pattern
diff --git a/tests/ui/or-patterns/remove-leading-vert.stderr b/tests/ui/or-patterns/remove-leading-vert.stderr
index af51c67e1c8..5177e98f0d9 100644
--- a/tests/ui/or-patterns/remove-leading-vert.stderr
+++ b/tests/ui/or-patterns/remove-leading-vert.stderr
@@ -2,161 +2,279 @@ error: top-level or-patterns are not allowed in function parameters
   --> $DIR/remove-leading-vert.rs:11:14
    |
 LL |     fn fun1( | A: E) {}
-   |              ^^^ help: remove the `|`: `A`
+   |              ^^^
+   |
+help: remove the `|`
+   |
+LL -     fn fun1( | A: E) {}
+LL +     fn fun1(  A: E) {}
+   |
 
 error: unexpected `||` before function parameter
   --> $DIR/remove-leading-vert.rs:12:14
    |
 LL |     fn fun2( || A: E) {}
-   |              ^^ help: remove the `||`
+   |              ^^
    |
    = note: alternatives in or-patterns are separated with `|`, not `||`
+help: remove the `||`
+   |
+LL -     fn fun2( || A: E) {}
+LL +     fn fun2(  A: E) {}
+   |
 
 error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:14:11
    |
 LL |     let ( || A): (E);
-   |           ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |           ^^
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |     let ( | A): (E);
+   |           ~
 
 error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:17:11
    |
 LL |     let [ || A ]: [E; 1];
-   |           ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |           ^^
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |     let [ | A ]: [E; 1];
+   |           ~
 
 error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:19:13
    |
 LL |     let TS( || A ): TS;
-   |             ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |             ^^
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |     let TS( | A ): TS;
+   |             ~
 
 error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:21:17
    |
 LL |     let NS { f: || A }: NS;
-   |                 ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |                 ^^
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |     let NS { f: | A }: NS;
+   |                 ~
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:26:13
    |
 LL |     let ( A | ): E;
-   |           - ^ help: remove the `|`
+   |           - ^
    |           |
    |           while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let ( A | ): E;
+LL +     let ( A  ): E;
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:27:12
    |
 LL |     let (a |,): (E,);
-   |          - ^ help: remove the `|`
+   |          - ^
    |          |
    |          while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let (a |,): (E,);
+LL +     let (a ,): (E,);
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:28:17
    |
 LL |     let ( A | B | ): E;
-   |           -     ^ help: remove the `|`
+   |           -     ^
    |           |
    |           while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let ( A | B | ): E;
+LL +     let ( A | B  ): E;
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:29:17
    |
 LL |     let [ A | B | ]: [E; 1];
-   |           -     ^ help: remove the `|`
+   |           -     ^
    |           |
    |           while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let [ A | B | ]: [E; 1];
+LL +     let [ A | B  ]: [E; 1];
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:30:18
    |
 LL |     let S { f: B | };
-   |                - ^ help: remove the `|`
+   |                - ^
    |                |
    |                while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let S { f: B | };
+LL +     let S { f: B  };
+   |
 
 error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:31:13
    |
 LL |     let ( A || B | ): E;
-   |           - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |           - ^^
    |           |
    |           while parsing this or-pattern starting here
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |     let ( A | B | ): E;
+   |             ~
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:31:18
    |
 LL |     let ( A || B | ): E;
-   |           -      ^ help: remove the `|`
+   |           -      ^
    |           |
    |           while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let ( A || B | ): E;
+LL +     let ( A || B  ): E;
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:34:11
    |
 LL |         A | => {}
-   |         - ^ help: remove the `|`
+   |         - ^
    |         |
    |         while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -         A | => {}
+LL +         A  => {}
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:35:11
    |
 LL |         A || => {}
-   |         - ^^ help: remove the `||`
+   |         - ^^
    |         |
    |         while parsing this or-pattern starting here
    |
    = note: alternatives in or-patterns are separated with `|`, not `||`
+help: remove the `||`
+   |
+LL -         A || => {}
+LL +         A  => {}
+   |
 
 error: unexpected token `||` in pattern
   --> $DIR/remove-leading-vert.rs:36:11
    |
 LL |         A || B | => {}
-   |         - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         - ^^
    |         |
    |         while parsing this or-pattern starting here
+   |
+help: use a single `|` to separate multiple alternative patterns
+   |
+LL |         A | B | => {}
+   |           ~
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:36:16
    |
 LL |         A || B | => {}
-   |         -      ^ help: remove the `|`
+   |         -      ^
    |         |
    |         while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -         A || B | => {}
+LL +         A || B  => {}
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:38:17
    |
 LL |         | A | B | => {}
-   |         -       ^ help: remove the `|`
+   |         -       ^
    |         |
    |         while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -         | A | B | => {}
+LL +         | A | B  => {}
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:45:11
    |
 LL |     let a | : u8 = 0;
-   |         - ^ help: remove the `|`
+   |         - ^
    |         |
    |         while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let a | : u8 = 0;
+LL +     let a  : u8 = 0;
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:46:11
    |
 LL |     let a | = 0;
-   |         - ^ help: remove the `|`
+   |         - ^
    |         |
    |         while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let a | = 0;
+LL +     let a  = 0;
+   |
 
 error: a trailing `|` is not allowed in an or-pattern
   --> $DIR/remove-leading-vert.rs:47:11
    |
 LL |     let a | ;
-   |         - ^ help: remove the `|`
+   |         - ^
    |         |
    |         while parsing this or-pattern starting here
+   |
+help: remove the `|`
+   |
+LL -     let a | ;
+LL +     let a  ;
+   |
 
 error: aborting due to 21 previous errors
 
diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
index 3593c5182ce..1ba130e20b5 100644
--- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
@@ -154,9 +154,14 @@ error: outer attributes are not allowed on `if` and `else` branches
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
    |                                --   ^^^^^^^ -- the attributes are attached to this branch
-   |                                |    |
-   |                                |    help: remove the attributes
+   |                                |
    |                                the branch belongs to this `if`
+   |
+help: remove the attributes
+   |
+LL - #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
+LL + #[cfg(FALSE)] fn e() { let _ = if 0 {}; }
+   |
 
 error: an inner attribute is not permitted in this context
   --> $DIR/attr-stmt-expr-attr-bad.rs:40:38
@@ -178,9 +183,14 @@ error: outer attributes are not allowed on `if` and `else` branches
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
    |                                        ---- ^^^^^^^ -- the attributes are attached to this branch
-   |                                        |    |
-   |                                        |    help: remove the attributes
+   |                                        |
    |                                        the branch belongs to this `else`
+   |
+help: remove the attributes
+   |
+LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
+LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else {}; }
+   |
 
 error: an inner attribute is not permitted in this context
   --> $DIR/attr-stmt-expr-attr-bad.rs:46:46
@@ -196,18 +206,28 @@ error: outer attributes are not allowed on `if` and `else` branches
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
    |                                        ---- ^^^^^^^ ------- the attributes are attached to this branch
-   |                                        |    |
-   |                                        |    help: remove the attributes
+   |                                        |
    |                                        the branch belongs to this `else`
+   |
+help: remove the attributes
+   |
+LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
+LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; }
+   |
 
 error: outer attributes are not allowed on `if` and `else` branches
   --> $DIR/attr-stmt-expr-attr-bad.rs:50:50
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
    |                                             --   ^^^^^^^ -- the attributes are attached to this branch
-   |                                             |    |
-   |                                             |    help: remove the attributes
+   |                                             |
    |                                             the branch belongs to this `if`
+   |
+help: remove the attributes
+   |
+LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
+LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; }
+   |
 
 error: an inner attribute is not permitted in this context
   --> $DIR/attr-stmt-expr-attr-bad.rs:52:51
@@ -223,9 +243,14 @@ error: outer attributes are not allowed on `if` and `else` branches
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
    |                                --           ^^^^^^^ -- the attributes are attached to this branch
-   |                                |            |
-   |                                |            help: remove the attributes
+   |                                |
    |                                the branch belongs to this `if`
+   |
+help: remove the attributes
+   |
+LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
+LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {}; }
+   |
 
 error: an inner attribute is not permitted in this context
   --> $DIR/attr-stmt-expr-attr-bad.rs:56:46
@@ -247,9 +272,14 @@ error: outer attributes are not allowed on `if` and `else` branches
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
    |                                                ---- ^^^^^^^ -- the attributes are attached to this branch
-   |                                                |    |
-   |                                                |    help: remove the attributes
+   |                                                |
    |                                                the branch belongs to this `else`
+   |
+help: remove the attributes
+   |
+LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
+LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {}; }
+   |
 
 error: an inner attribute is not permitted in this context
   --> $DIR/attr-stmt-expr-attr-bad.rs:62:54
@@ -265,18 +295,28 @@ error: outer attributes are not allowed on `if` and `else` branches
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
    |                                                ---- ^^^^^^^ --------------- the attributes are attached to this branch
-   |                                                |    |
-   |                                                |    help: remove the attributes
+   |                                                |
    |                                                the branch belongs to this `else`
+   |
+help: remove the attributes
+   |
+LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
+LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; }
+   |
 
 error: outer attributes are not allowed on `if` and `else` branches
   --> $DIR/attr-stmt-expr-attr-bad.rs:66:66
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
    |                                                     --           ^^^^^^^ -- the attributes are attached to this branch
-   |                                                     |            |
-   |                                                     |            help: remove the attributes
+   |                                                     |
    |                                                     the branch belongs to this `if`
+   |
+help: remove the attributes
+   |
+LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
+LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; }
+   |
 
 error: an inner attribute is not permitted in this context
   --> $DIR/attr-stmt-expr-attr-bad.rs:68:67
@@ -361,9 +401,14 @@ error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:85:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
-   |                                   ^^^ help: use `..` instead
+   |                                   ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
+LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] 10 => () } }
+   |
 
 error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:85:38
@@ -375,9 +420,14 @@ error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:88:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
-   |                                   ^^^ help: use `..` instead
+   |                                   ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
+LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] -10 => () } }
+   |
 
 error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:88:38
@@ -395,9 +445,14 @@ error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:93:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
-   |                                   ^^^ help: use `..` instead
+   |                                   ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
+LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] FOO => () } }
+   |
 
 error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:93:38
diff --git a/tests/ui/parser/bad-char-literals.stderr b/tests/ui/parser/bad-char-literals.stderr
index a22ddbac1b9..89253d7d4aa 100644
--- a/tests/ui/parser/bad-char-literals.stderr
+++ b/tests/ui/parser/bad-char-literals.stderr
@@ -2,7 +2,12 @@ error: character constant must be escaped: `'`
   --> $DIR/bad-char-literals.rs:6:6
    |
 LL |     ''';
-   |      ^ help: escape the character: `\'`
+   |      ^
+   |
+help: escape the character
+   |
+LL |     '\'';
+   |      ~~
 
 error: character constant must be escaped: `\n`
   --> $DIR/bad-char-literals.rs:10:6
@@ -10,19 +15,34 @@ error: character constant must be escaped: `\n`
 LL |       '
    |  ______^
 LL | | ';
-   | |_ help: escape the character: `\n`
+   | |_
+   |
+help: escape the character
+   |
+LL |     '\n';
+   |      ++
 
 error: character constant must be escaped: `\r`
   --> $DIR/bad-char-literals.rs:15:6
    |
 LL |     '
';
-   |      ^ help: escape the character: `\r`
+   |      ^
+   |
+help: escape the character
+   |
+LL |     '\r';
+   |      ++
 
 error: character constant must be escaped: `\t`
   --> $DIR/bad-char-literals.rs:18:6
    |
 LL |     '    ';
-   |      ^^^^ help: escape the character: `\t`
+   |      ^^^^
+   |
+help: escape the character
+   |
+LL |     '\t';
+   |      ++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
index 265e31329ca..523ee47b0c9 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
@@ -5,7 +5,12 @@ LL | pub type T0 = const fn();
    |               -----^^^^^
    |               |
    |               `const` because of this
-   |               help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - pub type T0 = const fn();
+LL + pub type T0 =  fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:6:15
@@ -14,7 +19,12 @@ LL | pub type T1 = const extern "C" fn();
    |               -----^^^^^^^^^^^^^^^^
    |               |
    |               `const` because of this
-   |               help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - pub type T1 = const extern "C" fn();
+LL + pub type T1 =  extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:7:15
@@ -23,7 +33,12 @@ LL | pub type T2 = const unsafe extern fn();
    |               -----^^^^^^^^^^^^^^^^^^^
    |               |
    |               `const` because of this
-   |               help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - pub type T2 = const unsafe extern fn();
+LL + pub type T2 =  unsafe extern fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:8:15
@@ -32,7 +47,12 @@ LL | pub type T3 = async fn();
    |               -----^^^^^
    |               |
    |               `async` because of this
-   |               help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - pub type T3 = async fn();
+LL + pub type T3 =  fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:9:15
@@ -41,7 +61,12 @@ LL | pub type T4 = async extern fn();
    |               -----^^^^^^^^^^^^
    |               |
    |               `async` because of this
-   |               help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - pub type T4 = async extern fn();
+LL + pub type T4 =  extern fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:10:15
@@ -50,7 +75,12 @@ LL | pub type T5 = async unsafe extern "C" fn();
    |               -----^^^^^^^^^^^^^^^^^^^^^^^
    |               |
    |               `async` because of this
-   |               help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - pub type T5 = async unsafe extern "C" fn();
+LL + pub type T5 =  unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:11:15
@@ -59,7 +89,12 @@ LL | pub type T6 = const async unsafe extern "C" fn();
    |               -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |               |
    |               `const` because of this
-   |               help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - pub type T6 = const async unsafe extern "C" fn();
+LL + pub type T6 =  async unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:11:15
@@ -68,7 +103,12 @@ LL | pub type T6 = const async unsafe extern "C" fn();
    |               ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
    |                     |
    |                     `async` because of this
-   |                     help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - pub type T6 = const async unsafe extern "C" fn();
+LL + pub type T6 = const  unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:15:17
@@ -77,7 +117,12 @@ LL | pub type FTT0 = for<'a> const fn();
    |                 ^^^^^^^^-----^^^^^
    |                         |
    |                         `const` because of this
-   |                         help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - pub type FTT0 = for<'a> const fn();
+LL + pub type FTT0 = for<'a>  fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:16:17
@@ -86,7 +131,12 @@ LL | pub type FTT1 = for<'a> const extern "C" fn();
    |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^
    |                         |
    |                         `const` because of this
-   |                         help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - pub type FTT1 = for<'a> const extern "C" fn();
+LL + pub type FTT1 = for<'a>  extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:17:17
@@ -95,7 +145,12 @@ LL | pub type FTT2 = for<'a> const unsafe extern fn();
    |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^
    |                         |
    |                         `const` because of this
-   |                         help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - pub type FTT2 = for<'a> const unsafe extern fn();
+LL + pub type FTT2 = for<'a>  unsafe extern fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:18:17
@@ -104,7 +159,12 @@ LL | pub type FTT3 = for<'a> async fn();
    |                 ^^^^^^^^-----^^^^^
    |                         |
    |                         `async` because of this
-   |                         help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - pub type FTT3 = for<'a> async fn();
+LL + pub type FTT3 = for<'a>  fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:19:17
@@ -113,7 +173,12 @@ LL | pub type FTT4 = for<'a> async extern fn();
    |                 ^^^^^^^^-----^^^^^^^^^^^^
    |                         |
    |                         `async` because of this
-   |                         help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - pub type FTT4 = for<'a> async extern fn();
+LL + pub type FTT4 = for<'a>  extern fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:20:17
@@ -122,7 +187,12 @@ LL | pub type FTT5 = for<'a> async unsafe extern "C" fn();
    |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
    |                         |
    |                         `async` because of this
-   |                         help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - pub type FTT5 = for<'a> async unsafe extern "C" fn();
+LL + pub type FTT5 = for<'a>  unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:22:17
@@ -131,7 +201,12 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn();
    |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                         |
    |                         `const` because of this
-   |                         help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn();
+LL + pub type FTT6 = for<'a>  async unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:22:17
@@ -140,7 +215,12 @@ LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn();
    |                 ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
    |                               |
    |                               `async` because of this
-   |                               help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn();
+LL + pub type FTT6 = for<'a> const  unsafe extern "C" fn();
+   |
 
 error: aborting due to 16 previous errors
 
diff --git a/tests/ui/parser/byte-literals.stderr b/tests/ui/parser/byte-literals.stderr
index 5b414c8927e..25e31995441 100644
--- a/tests/ui/parser/byte-literals.stderr
+++ b/tests/ui/parser/byte-literals.stderr
@@ -24,13 +24,23 @@ error: byte constant must be escaped: `\t`
   --> $DIR/byte-literals.rs:8:7
    |
 LL |     b'    ';
-   |       ^^^^ help: escape the character: `\t`
+   |       ^^^^
+   |
+help: escape the character
+   |
+LL |     b'\t';
+   |       ++
 
 error: byte constant must be escaped: `'`
   --> $DIR/byte-literals.rs:9:7
    |
 LL |     b''';
-   |       ^ help: escape the character: `\'`
+   |       ^
+   |
+help: escape the character
+   |
+LL |     b'\'';
+   |       ~~
 
 error: non-ASCII character in byte literal
   --> $DIR/byte-literals.rs:10:7
diff --git a/tests/ui/parser/char/whitespace-character-literal.stderr b/tests/ui/parser/char/whitespace-character-literal.stderr
index 3bd048f8f62..f273b5d61d5 100644
--- a/tests/ui/parser/char/whitespace-character-literal.stderr
+++ b/tests/ui/parser/char/whitespace-character-literal.stderr
@@ -2,15 +2,17 @@ error: character literal may only contain one codepoint
   --> $DIR/whitespace-character-literal.rs:5:30
    |
 LL |     let _hair_space_around = ' x​';
-   |                              ^--^
-   |                               |
-   |                               help: consider removing the non-printing characters: `x`
+   |                              ^^^^
    |
 note: there are non-printing characters, the full sequence is `\u{200a}x\u{200b}`
   --> $DIR/whitespace-character-literal.rs:5:31
    |
 LL |     let _hair_space_around = ' x​';
    |                               ^^
+help: consider removing the non-printing characters
+   |
+LL |     let _hair_space_around = 'x​';
+   |                               ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/default-on-wrong-item-kind.stderr b/tests/ui/parser/default-on-wrong-item-kind.stderr
index af513f7617b..392c85e0c43 100644
--- a/tests/ui/parser/default-on-wrong-item-kind.stderr
+++ b/tests/ui/parser/default-on-wrong-item-kind.stderr
@@ -154,11 +154,13 @@ error: extern items cannot be `const`
   --> $DIR/default-on-wrong-item-kind.rs:38:19
    |
 LL |     default const foo: u8;
-   |     --------------^^^
-   |     |
-   |     help: try using a static value: `static`
+   |                   ^^^
    |
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+help: try using a static value
+   |
+LL |     static foo: u8;
+   |     ~~~~~~
 
 error: a module cannot be `default`
   --> $DIR/default-on-wrong-item-kind.rs:41:5
diff --git a/tests/ui/parser/do-catch-suggests-try.stderr b/tests/ui/parser/do-catch-suggests-try.stderr
index cd8907b7eac..fd3406ae29f 100644
--- a/tests/ui/parser/do-catch-suggests-try.stderr
+++ b/tests/ui/parser/do-catch-suggests-try.stderr
@@ -2,9 +2,13 @@ error: found removed `do catch` syntax
   --> $DIR/do-catch-suggests-try.rs:4:25
    |
 LL |     let _: Option<()> = do catch {};
-   |                         ^^^^^^^^ help: replace with the new syntax: `try`
+   |                         ^^^^^^^^
    |
    = note: following RFC #2388, the new non-placeholder syntax is `try`
+help: replace with the new syntax
+   |
+LL |     let _: Option<()> = try {};
+   |                         ~~~
 
 error[E0308]: mismatched types
   --> $DIR/do-catch-suggests-try.rs:9:33
diff --git a/tests/ui/parser/doc-comment-in-if-statement.stderr b/tests/ui/parser/doc-comment-in-if-statement.stderr
index fc0bc507370..37e0c398a61 100644
--- a/tests/ui/parser/doc-comment-in-if-statement.stderr
+++ b/tests/ui/parser/doc-comment-in-if-statement.stderr
@@ -16,9 +16,14 @@ error: outer attributes are not allowed on `if` and `else` branches
    |
 LL |     if true /*!*/ {}
    |     --      ^^^^^ -- the attributes are attached to this branch
-   |     |       |
-   |     |       help: remove the attributes
+   |     |
    |     the branch belongs to this `if`
+   |
+help: remove the attributes
+   |
+LL -     if true /*!*/ {}
+LL +     if true {}
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/expr-rarrow-call.stderr b/tests/ui/parser/expr-rarrow-call.stderr
index 90082f98cb5..221e3a74d79 100644
--- a/tests/ui/parser/expr-rarrow-call.stderr
+++ b/tests/ui/parser/expr-rarrow-call.stderr
@@ -2,41 +2,61 @@ error: `->` used for field access or method call
   --> $DIR/expr-rarrow-call.rs:14:10
    |
 LL |     named->foo;
-   |          ^^ help: try using `.` instead
+   |          ^^
    |
    = help: the `.` operator will dereference the value if needed
+help: try using `.` instead
+   |
+LL |     named.foo;
+   |          ~
 
 error: `->` used for field access or method call
   --> $DIR/expr-rarrow-call.rs:18:12
    |
 LL |     unnamed->0;
-   |            ^^ help: try using `.` instead
+   |            ^^
    |
    = help: the `.` operator will dereference the value if needed
+help: try using `.` instead
+   |
+LL |     unnamed.0;
+   |            ~
 
 error: `->` used for field access or method call
   --> $DIR/expr-rarrow-call.rs:22:6
    |
 LL |     t->0;
-   |      ^^ help: try using `.` instead
+   |      ^^
    |
    = help: the `.` operator will dereference the value if needed
+help: try using `.` instead
+   |
+LL |     t.0;
+   |      ~
 
 error: `->` used for field access or method call
   --> $DIR/expr-rarrow-call.rs:23:6
    |
 LL |     t->1;
-   |      ^^ help: try using `.` instead
+   |      ^^
    |
    = help: the `.` operator will dereference the value if needed
+help: try using `.` instead
+   |
+LL |     t.1;
+   |      ~
 
 error: `->` used for field access or method call
   --> $DIR/expr-rarrow-call.rs:30:8
    |
 LL |     foo->clone();
-   |        ^^ help: try using `.` instead
+   |        ^^
    |
    = help: the `.` operator will dereference the value if needed
+help: try using `.` instead
+   |
+LL |     foo.clone();
+   |        ~
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/parser/fn-colon-return-type.stderr b/tests/ui/parser/fn-colon-return-type.stderr
index b61a62a17f7..c1cdf4d4975 100644
--- a/tests/ui/parser/fn-colon-return-type.stderr
+++ b/tests/ui/parser/fn-colon-return-type.stderr
@@ -2,7 +2,12 @@ error: return types are denoted using `->`
   --> $DIR/fn-colon-return-type.rs:1:15
    |
 LL | fn foo(x: i32): i32 {
-   |               ^ help: use `->` instead
+   |               ^
+   |
+help: use `->` instead
+   |
+LL | fn foo(x: i32) -> i32 {
+   |                ~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/foreign-const-semantic-fail.stderr b/tests/ui/parser/foreign-const-semantic-fail.stderr
index 8dc66c0d012..d317847f98a 100644
--- a/tests/ui/parser/foreign-const-semantic-fail.stderr
+++ b/tests/ui/parser/foreign-const-semantic-fail.stderr
@@ -2,21 +2,25 @@ error: extern items cannot be `const`
   --> $DIR/foreign-const-semantic-fail.rs:4:11
    |
 LL |     const A: isize;
-   |     ------^
-   |     |
-   |     help: try using a static value: `static`
+   |           ^
    |
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+help: try using a static value
+   |
+LL |     static A: isize;
+   |     ~~~~~~
 
 error: extern items cannot be `const`
   --> $DIR/foreign-const-semantic-fail.rs:6:11
    |
 LL |     const B: isize = 42;
-   |     ------^
-   |     |
-   |     help: try using a static value: `static`
+   |           ^
    |
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+help: try using a static value
+   |
+LL |     static B: isize = 42;
+   |     ~~~~~~
 
 error: incorrect `static` inside `extern` block
   --> $DIR/foreign-const-semantic-fail.rs:6:11
diff --git a/tests/ui/parser/foreign-const-syntactic-fail.stderr b/tests/ui/parser/foreign-const-syntactic-fail.stderr
index 9cf58fa95fb..7da2c019022 100644
--- a/tests/ui/parser/foreign-const-syntactic-fail.stderr
+++ b/tests/ui/parser/foreign-const-syntactic-fail.stderr
@@ -2,21 +2,25 @@ error: extern items cannot be `const`
   --> $DIR/foreign-const-syntactic-fail.rs:7:11
    |
 LL |     const A: isize;
-   |     ------^
-   |     |
-   |     help: try using a static value: `static`
+   |           ^
    |
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+help: try using a static value
+   |
+LL |     static A: isize;
+   |     ~~~~~~
 
 error: extern items cannot be `const`
   --> $DIR/foreign-const-syntactic-fail.rs:8:11
    |
 LL |     const B: isize = 42;
-   |     ------^
-   |     |
-   |     help: try using a static value: `static`
+   |           ^
    |
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+help: try using a static value
+   |
+LL |     static B: isize = 42;
+   |     ~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/ice-issue-127600.rs b/tests/ui/parser/ice-issue-127600.rs
new file mode 100644
index 00000000000..709c1025326
--- /dev/null
+++ b/tests/ui/parser/ice-issue-127600.rs
@@ -0,0 +1,2 @@
+const!(&raw mut a);
+//~^ ERROR expected identifier, found `!`
diff --git a/tests/ui/parser/ice-issue-127600.stderr b/tests/ui/parser/ice-issue-127600.stderr
new file mode 100644
index 00000000000..629fc4ae40b
--- /dev/null
+++ b/tests/ui/parser/ice-issue-127600.stderr
@@ -0,0 +1,8 @@
+error: expected identifier, found `!`
+  --> $DIR/ice-issue-127600.rs:1:6
+   |
+LL | const!(&raw mut a);
+   |      ^ expected identifier
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/ident-recovery.stderr b/tests/ui/parser/ident-recovery.stderr
index e9a55026d12..83666014eb2 100644
--- a/tests/ui/parser/ident-recovery.stderr
+++ b/tests/ui/parser/ident-recovery.stderr
@@ -2,19 +2,25 @@ error: expected identifier, found `,`
   --> $DIR/ident-recovery.rs:1:4
    |
 LL | fn ,comma() {
-   |    ^
-   |    |
-   |    expected identifier
-   |    help: remove this comma
+   |    ^ expected identifier
+   |
+help: remove this comma
+   |
+LL - fn ,comma() {
+LL + fn comma() {
+   |
 
 error: expected identifier, found `,`
   --> $DIR/ident-recovery.rs:4:16
    |
 LL |         x: i32,,
-   |                ^
-   |                |
-   |                expected identifier
-   |                help: remove this comma
+   |                ^ expected identifier
+   |
+help: remove this comma
+   |
+LL -         x: i32,,
+LL +         x: i32,
+   |
 
 error: expected identifier, found keyword `break`
   --> $DIR/ident-recovery.rs:10:4
diff --git a/tests/ui/parser/if-in-in.stderr b/tests/ui/parser/if-in-in.stderr
index 6117370c0ce..d8def76792e 100644
--- a/tests/ui/parser/if-in-in.stderr
+++ b/tests/ui/parser/if-in-in.stderr
@@ -2,9 +2,13 @@ error: expected iterable, found keyword `in`
   --> $DIR/if-in-in.rs:4:14
    |
 LL |     for i in in 1..2 {
-   |           ---^^
-   |           |
-   |           help: remove the duplicated `in`
+   |              ^^
+   |
+help: remove the duplicated `in`
+   |
+LL -     for i in in 1..2 {
+LL +     for i in 1..2 {
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/impl-parsing.stderr b/tests/ui/parser/impl-parsing.stderr
index a57cc075ccc..6a24a9453e6 100644
--- a/tests/ui/parser/impl-parsing.stderr
+++ b/tests/ui/parser/impl-parsing.stderr
@@ -2,13 +2,23 @@ error: missing `for` in a trait impl
   --> $DIR/impl-parsing.rs:4:11
    |
 LL | impl Trait Type {}
-   |           ^ help: add `for` here
+   |           ^
+   |
+help: add `for` here
+   |
+LL | impl Trait for Type {}
+   |            +++
 
 error: missing `for` in a trait impl
   --> $DIR/impl-parsing.rs:5:11
    |
 LL | impl Trait .. {}
-   |           ^ help: add `for` here
+   |           ^
+   |
+help: add `for` here
+   |
+LL | impl Trait for .. {}
+   |            +++
 
 error: expected a trait, found type
   --> $DIR/impl-parsing.rs:6:6
diff --git a/tests/ui/parser/intersection-patterns-1.stderr b/tests/ui/parser/intersection-patterns-1.stderr
index dc968656c91..ed2466b21a7 100644
--- a/tests/ui/parser/intersection-patterns-1.stderr
+++ b/tests/ui/parser/intersection-patterns-1.stderr
@@ -6,7 +6,11 @@ LL |         Some(x) @ y => {}
    |         |         |
    |         |         binding on the right, should be on the left
    |         pattern on the left, should be on the right
-   |         help: switch the order: `y @ Some(x)`
+   |
+help: switch the order
+   |
+LL |         y @ Some(x) => {}
+   |         ~~~~~~~~~~~
 
 error: pattern on wrong side of `@`
   --> $DIR/intersection-patterns-1.rs:27:9
@@ -16,7 +20,11 @@ LL |         1 ..= 5 @ e => {}
    |         |         |
    |         |         binding on the right, should be on the left
    |         pattern on the left, should be on the right
-   |         help: switch the order: `e @ 1..=5`
+   |
+help: switch the order
+   |
+LL |         e @ 1..=5 => {}
+   |         ~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs
index 3c0059ba3e3..c9fb08506dd 100644
--- a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs
+++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs
@@ -2,5 +2,6 @@
 // Tests that we do not erroneously emit an error about
 // missing main function when the mod starts with a `;`
 
-; //~ ERROR expected item, found `;`
+;
+//~^ ERROR expected item, found `;`
 fn main() { }
diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr
index 9776677589f..002dc028cf5 100644
--- a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr
+++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr
@@ -2,7 +2,12 @@ error: expected item, found `;`
   --> $DIR/fn-no-semicolon-issue-124935-semi-after-item.rs:5:1
    |
 LL | ;
-   | ^ help: remove this semicolon
+   | ^
+   |
+help: remove this semicolon
+   |
+LL - ;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-100197-mut-let.stderr b/tests/ui/parser/issues/issue-100197-mut-let.stderr
index 07d13688140..252ed7d0715 100644
--- a/tests/ui/parser/issues/issue-100197-mut-let.stderr
+++ b/tests/ui/parser/issues/issue-100197-mut-let.stderr
@@ -2,7 +2,12 @@ error: invalid variable declaration
   --> $DIR/issue-100197-mut-let.rs:4:5
    |
 LL |     mut let _x = 123;
-   |     ^^^^^^^ help: switch the order of `mut` and `let`: `let mut`
+   |     ^^^^^^^
+   |
+help: switch the order of `mut` and `let`
+   |
+LL |     let mut _x = 123;
+   |     ~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-101477-enum.stderr b/tests/ui/parser/issues/issue-101477-enum.stderr
index 94130671f1c..c6dadeab8b3 100644
--- a/tests/ui/parser/issues/issue-101477-enum.stderr
+++ b/tests/ui/parser/issues/issue-101477-enum.stderr
@@ -2,9 +2,14 @@ error: unexpected `==`
   --> $DIR/issue-101477-enum.rs:6:7
    |
 LL |     B == 2
-   |       ^^ help: try using `=` instead
+   |       ^^
    |
    = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+help: try using `=` instead
+   |
+LL -     B == 2
+LL +     B = 2
+   |
 
 error: expected item, found `==`
   --> $DIR/issue-101477-enum.rs:6:7
diff --git a/tests/ui/parser/issues/issue-101477-let.stderr b/tests/ui/parser/issues/issue-101477-let.stderr
index 56348357397..59e90c8102f 100644
--- a/tests/ui/parser/issues/issue-101477-let.stderr
+++ b/tests/ui/parser/issues/issue-101477-let.stderr
@@ -2,7 +2,13 @@ error: unexpected `==`
   --> $DIR/issue-101477-let.rs:4:11
    |
 LL |     let x == 2;
-   |           ^^ help: try using `=` instead
+   |           ^^
+   |
+help: try using `=` instead
+   |
+LL -     let x == 2;
+LL +     let x = 2;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr b/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr
index 86d3449cc33..e5c6ba27755 100644
--- a/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr
+++ b/tests/ui/parser/issues/issue-108109-fn-missing-params.stderr
@@ -2,13 +2,23 @@ error: missing parameters for function definition
   --> $DIR/issue-108109-fn-missing-params.rs:3:15
    |
 LL | pub fn missing -> () {}
-   |               ^ help: add a parameter list
+   |               ^
+   |
+help: add a parameter list
+   |
+LL | pub fn missing() -> () {}
+   |               ++
 
 error: missing parameters for function definition
   --> $DIR/issue-108109-fn-missing-params.rs:6:16
    |
 LL | pub fn missing2 {}
-   |                ^ help: add a parameter list
+   |                ^
+   |
+help: add a parameter list
+   |
+LL | pub fn missing2() {}
+   |                ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-113203.stderr b/tests/ui/parser/issues/issue-113203.stderr
index 5db628d5977..1ef20ddf726 100644
--- a/tests/ui/parser/issues/issue-113203.stderr
+++ b/tests/ui/parser/issues/issue-113203.stderr
@@ -2,7 +2,13 @@ error: incorrect use of `await`
   --> $DIR/issue-113203.rs:5:5
    |
 LL |     await {}()
-   |     ^^^^^^^^ help: `await` is a postfix operation: `{}.await`
+   |     ^^^^^^^^
+   |
+help: `await` is a postfix operation
+   |
+LL -     await {}()
+LL +     {}.await()
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr
index 75c6a40c744..3519fb8777f 100644
--- a/tests/ui/parser/issues/issue-118530-ice.stderr
+++ b/tests/ui/parser/issues/issue-118530-ice.stderr
@@ -37,9 +37,13 @@ error: `->` used for field access or method call
   --> $DIR/issue-118530-ice.rs:5:20
    |
 LL |     attr::fn bar() -> String {
-   |                    ^^ help: try using `.` instead
+   |                    ^^
    |
    = help: the `.` operator will dereference the value if needed
+help: try using `.` instead
+   |
+LL |     attr::fn bar() . String {
+   |                    ~
 
 error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{`
   --> $DIR/issue-118530-ice.rs:5:30
diff --git a/tests/ui/parser/issues/issue-17718-const-mut.stderr b/tests/ui/parser/issues/issue-17718-const-mut.stderr
index a27f517086e..54b819c3cfb 100644
--- a/tests/ui/parser/issues/issue-17718-const-mut.stderr
+++ b/tests/ui/parser/issues/issue-17718-const-mut.stderr
@@ -1,10 +1,13 @@
 error: const globals cannot be mutable
   --> $DIR/issue-17718-const-mut.rs:2:1
    |
-LL | const
-   | ----- help: you might want to declare a static instead: `static`
 LL | mut
    | ^^^ cannot be mutable
+   |
+help: you might want to declare a static instead
+   |
+LL | static
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr b/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr
index 88d97c795fc..4a3743579e7 100644
--- a/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr
+++ b/tests/ui/parser/issues/issue-23620-invalid-escapes.stderr
@@ -86,9 +86,12 @@ error: incorrect unicode escape sequence
   --> $DIR/issue-23620-invalid-escapes.rs:32:14
    |
 LL |     let _ = "\u8f";
-   |              ^^^-
-   |              |
-   |              help: format of unicode escape sequences uses braces: `\u{8f}`
+   |              ^^^
+   |
+help: format of unicode escape sequences uses braces
+   |
+LL |     let _ = "\u{8f}";
+   |              ~~~~~~
 
 error: aborting due to 13 previous errors
 
diff --git a/tests/ui/parser/issues/issue-27255.stderr b/tests/ui/parser/issues/issue-27255.stderr
index 391a23556c4..2cd7ebd60b1 100644
--- a/tests/ui/parser/issues/issue-27255.stderr
+++ b/tests/ui/parser/issues/issue-27255.stderr
@@ -2,13 +2,23 @@ error: missing `for` in a trait impl
   --> $DIR/issue-27255.rs:3:7
    |
 LL | impl A .. {}
-   |       ^ help: add `for` here
+   |       ^
+   |
+help: add `for` here
+   |
+LL | impl A for .. {}
+   |        +++
 
 error: missing `for` in a trait impl
   --> $DIR/issue-27255.rs:7:7
    |
 LL | impl A      usize {}
-   |       ^^^^^^ help: add `for` here
+   |       ^^^^^^
+   |
+help: add `for` here
+   |
+LL | impl A for usize {}
+   |        +++
 
 error: `impl Trait for .. {}` is an obsolete syntax
   --> $DIR/issue-27255.rs:3:1
diff --git a/tests/ui/parser/issues/issue-32501.stderr b/tests/ui/parser/issues/issue-32501.stderr
index c0513a64039..b0ec135b784 100644
--- a/tests/ui/parser/issues/issue-32501.stderr
+++ b/tests/ui/parser/issues/issue-32501.stderr
@@ -2,9 +2,14 @@ error: `mut` must be followed by a named binding
   --> $DIR/issue-32501.rs:7:9
    |
 LL |     let mut _ = 0;
-   |         ^^^^ help: remove the `mut` prefix
+   |         ^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: remove the `mut` prefix
+   |
+LL -     let mut _ = 0;
+LL +     let _ = 0;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-46186.stderr b/tests/ui/parser/issues/issue-46186.stderr
index c67c271e19a..5ea3e1f4983 100644
--- a/tests/ui/parser/issues/issue-46186.stderr
+++ b/tests/ui/parser/issues/issue-46186.stderr
@@ -2,9 +2,14 @@ error: expected item, found `;`
   --> $DIR/issue-46186.rs:5:2
    |
 LL | };
-   |  ^ help: remove this semicolon
+   |  ^
    |
    = help: braced struct declarations are not followed by a semicolon
+help: remove this semicolon
+   |
+LL - };
+LL + }
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-48636.stderr b/tests/ui/parser/issues/issue-48636.stderr
index 488a046a549..c17a8ec2f89 100644
--- a/tests/ui/parser/issues/issue-48636.stderr
+++ b/tests/ui/parser/issues/issue-48636.stderr
@@ -4,11 +4,14 @@ error[E0585]: found a documentation comment that doesn't document anything
 LL | struct S {
    |        - while parsing this struct
 LL |     x: u8
-   |          - help: missing comma here: `,`
 LL |     /// The ID of the parent core
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: doc comments must come before what they document, if a comment was intended use `//`
+help: missing comma here
+   |
+LL |     x: u8,
+   |          +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-49040.stderr b/tests/ui/parser/issues/issue-49040.stderr
index 11ef5e1aadf..c25d5683ecf 100644
--- a/tests/ui/parser/issues/issue-49040.stderr
+++ b/tests/ui/parser/issues/issue-49040.stderr
@@ -2,7 +2,13 @@ error: expected item, found `;`
   --> $DIR/issue-49040.rs:1:28
    |
 LL | #![allow(unused_variables)];
-   |                            ^ help: remove this semicolon
+   |                            ^
+   |
+help: remove this semicolon
+   |
+LL - #![allow(unused_variables)];
+LL + #![allow(unused_variables)]
+   |
 
 error[E0601]: `main` function not found in crate `issue_49040`
   --> $DIR/issue-49040.rs:2:12
diff --git a/tests/ui/parser/issues/issue-52496.stderr b/tests/ui/parser/issues/issue-52496.stderr
index 78c81bf5b0d..a97effb4e0c 100644
--- a/tests/ui/parser/issues/issue-52496.stderr
+++ b/tests/ui/parser/issues/issue-52496.stderr
@@ -2,7 +2,12 @@ error: float literals must have an integer part
   --> $DIR/issue-52496.rs:4:24
    |
 LL |     let _ = Foo { bar: .5, baz: 42 };
-   |                        ^^ help: must have an integer part: `0.5`
+   |                        ^^
+   |
+help: must have an integer part
+   |
+LL |     let _ = Foo { bar: 0.5, baz: 42 };
+   |                        +
 
 error: expected one of `,`, `:`, or `}`, found `.`
   --> $DIR/issue-52496.rs:8:22
diff --git a/tests/ui/parser/issues/issue-54521-2.stderr b/tests/ui/parser/issues/issue-54521-2.stderr
index 9556b83b730..ad662ef1cca 100644
--- a/tests/ui/parser/issues/issue-54521-2.stderr
+++ b/tests/ui/parser/issues/issue-54521-2.stderr
@@ -2,25 +2,49 @@ error: unmatched angle brackets
   --> $DIR/issue-54521-2.rs:11:25
    |
 LL |     let _ = Vec::<usize>>>>>::new();
-   |                         ^^^^ help: remove extra angle brackets
+   |                         ^^^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = Vec::<usize>>>>>::new();
+LL +     let _ = Vec::<usize>::new();
+   |
 
 error: unmatched angle brackets
   --> $DIR/issue-54521-2.rs:14:25
    |
 LL |     let _ = Vec::<usize>>>>::new();
-   |                         ^^^ help: remove extra angle brackets
+   |                         ^^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = Vec::<usize>>>>::new();
+LL +     let _ = Vec::<usize>::new();
+   |
 
 error: unmatched angle brackets
   --> $DIR/issue-54521-2.rs:17:25
    |
 LL |     let _ = Vec::<usize>>>::new();
-   |                         ^^ help: remove extra angle brackets
+   |                         ^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = Vec::<usize>>>::new();
+LL +     let _ = Vec::<usize>::new();
+   |
 
 error: unmatched angle bracket
   --> $DIR/issue-54521-2.rs:20:25
    |
 LL |     let _ = Vec::<usize>>::new();
-   |                         ^ help: remove extra angle bracket
+   |                         ^
+   |
+help: remove extra angle bracket
+   |
+LL -     let _ = Vec::<usize>>::new();
+LL +     let _ = Vec::<usize>::new();
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/parser/issues/issue-54521-3.stderr b/tests/ui/parser/issues/issue-54521-3.stderr
index 0f23dd62107..bd468869b06 100644
--- a/tests/ui/parser/issues/issue-54521-3.stderr
+++ b/tests/ui/parser/issues/issue-54521-3.stderr
@@ -2,25 +2,49 @@ error: unmatched angle brackets
   --> $DIR/issue-54521-3.rs:11:60
    |
 LL |     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>>();
-   |                                                            ^^^^ help: remove extra angle brackets
+   |                                                            ^^^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>>();
+LL +     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+   |
 
 error: unmatched angle brackets
   --> $DIR/issue-54521-3.rs:14:60
    |
 LL |     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>();
-   |                                                            ^^^ help: remove extra angle brackets
+   |                                                            ^^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>();
+LL +     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+   |
 
 error: unmatched angle brackets
   --> $DIR/issue-54521-3.rs:17:60
    |
 LL |     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
-   |                                                            ^^ help: remove extra angle brackets
+   |                                                            ^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+LL +     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+   |
 
 error: unmatched angle bracket
   --> $DIR/issue-54521-3.rs:20:60
    |
 LL |     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>();
-   |                                                            ^ help: remove extra angle bracket
+   |                                                            ^
+   |
+help: remove extra angle bracket
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>();
+LL +     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/parser/issues/issue-57684.stderr b/tests/ui/parser/issues/issue-57684.stderr
index 514bbffde6b..39e1c8cd7cc 100644
--- a/tests/ui/parser/issues/issue-57684.stderr
+++ b/tests/ui/parser/issues/issue-57684.stderr
@@ -2,17 +2,23 @@ error: expected `:`, found `=`
   --> $DIR/issue-57684.rs:27:20
    |
 LL |     let _ = X { f1 = 5 };
-   |                   -^
-   |                   |
-   |                   help: replace equals symbol with a colon: `:`
+   |                    ^
+   |
+help: replace equals symbol with a colon
+   |
+LL |     let _ = X { f1: 5 };
+   |                   ~
 
 error: expected `:`, found `=`
   --> $DIR/issue-57684.rs:32:12
    |
 LL |         f1 = 5,
-   |           -^
-   |           |
-   |           help: replace equals symbol with a colon: `:`
+   |            ^
+   |
+help: replace equals symbol with a colon
+   |
+LL |         f1: 5,
+   |           ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-57819.stderr b/tests/ui/parser/issues/issue-57819.stderr
index 493e9835b1c..a01625d9c4c 100644
--- a/tests/ui/parser/issues/issue-57819.stderr
+++ b/tests/ui/parser/issues/issue-57819.stderr
@@ -2,43 +2,85 @@ error: unmatched angle brackets
   --> $DIR/issue-57819.rs:19:10
    |
 LL |     bar::<<<<<T as Foo>::Output>();
-   |          ^^^ help: remove extra angle brackets
+   |          ^^^
+   |
+help: remove extra angle brackets
+   |
+LL -     bar::<<<<<T as Foo>::Output>();
+LL +     bar::<<T as Foo>::Output>();
+   |
 
 error: unmatched angle brackets
   --> $DIR/issue-57819.rs:22:10
    |
 LL |     bar::<<<<T as Foo>::Output>();
-   |          ^^ help: remove extra angle brackets
+   |          ^^
+   |
+help: remove extra angle brackets
+   |
+LL -     bar::<<<<T as Foo>::Output>();
+LL +     bar::<<T as Foo>::Output>();
+   |
 
 error: unmatched angle bracket
   --> $DIR/issue-57819.rs:25:10
    |
 LL |     bar::<<<T as Foo>::Output>();
-   |          ^ help: remove extra angle bracket
+   |          ^
+   |
+help: remove extra angle bracket
+   |
+LL -     bar::<<<T as Foo>::Output>();
+LL +     bar::<<T as Foo>::Output>();
+   |
 
 error: unmatched angle brackets
   --> $DIR/issue-57819.rs:34:48
    |
 LL |     let _ = vec![1, 2, 3].into_iter().collect::<<<<<Vec<usize>>();
-   |                                                ^^^^ help: remove extra angle brackets
+   |                                                ^^^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().collect::<<<<<Vec<usize>>();
+LL +     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+   |
 
 error: unmatched angle brackets
   --> $DIR/issue-57819.rs:37:48
    |
 LL |     let _ = vec![1, 2, 3].into_iter().collect::<<<<Vec<usize>>();
-   |                                                ^^^ help: remove extra angle brackets
+   |                                                ^^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().collect::<<<<Vec<usize>>();
+LL +     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+   |
 
 error: unmatched angle brackets
   --> $DIR/issue-57819.rs:40:48
    |
 LL |     let _ = vec![1, 2, 3].into_iter().collect::<<<Vec<usize>>();
-   |                                                ^^ help: remove extra angle brackets
+   |                                                ^^
+   |
+help: remove extra angle brackets
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().collect::<<<Vec<usize>>();
+LL +     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+   |
 
 error: unmatched angle bracket
   --> $DIR/issue-57819.rs:43:48
    |
 LL |     let _ = vec![1, 2, 3].into_iter().collect::<<Vec<usize>>();
-   |                                                ^ help: remove extra angle bracket
+   |                                                ^
+   |
+help: remove extra angle bracket
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().collect::<<Vec<usize>>();
+LL +     let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+   |
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr
index 2bd87ee0c38..76259b40a93 100644
--- a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr
+++ b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr
@@ -2,13 +2,18 @@ error: `mut` must be followed by a named binding
   --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:6:13
    |
 LL |         let mut $eval = ();
-   |             ^^^^ help: remove the `mut` prefix
+   |             ^^^^
 ...
 LL |     mac1! { does_not_exist!() }
    |     --------------------------- in this macro invocation
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
    = note: this error originates in the macro `mac1` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: remove the `mut` prefix
+   |
+LL -         let mut $eval = ();
+LL +         let $eval = ();
+   |
 
 error: expected identifier, found `does_not_exist!()`
   --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:17
@@ -25,13 +30,18 @@ error: `mut` must be followed by a named binding
   --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:13
    |
 LL |         let mut $eval = ();
-   |             ^^^ help: remove the `mut` prefix
+   |             ^^^
 ...
 LL |     mac2! { does_not_exist!() }
    |     --------------------------- in this macro invocation
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
    = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: remove the `mut` prefix
+   |
+LL -         let mut $eval = ();
+LL +         let  $eval = ();
+   |
 
 error: cannot find macro `does_not_exist` in this scope
   --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13
diff --git a/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr b/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr
index 0a88dd2c4d3..49d091cf391 100644
--- a/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr
+++ b/tests/ui/parser/issues/issue-65257-invalid-var-decl-recovery.stderr
@@ -46,13 +46,23 @@ error: invalid variable declaration
   --> $DIR/issue-65257-invalid-var-decl-recovery.rs:14:5
    |
 LL |     mut n = 0;
-   |     ^^^ help: missing keyword: `let mut`
+   |     ^^^
+   |
+help: missing keyword
+   |
+LL |     let mut n = 0;
+   |     ~~~~~~~
 
 error: invalid variable declaration
   --> $DIR/issue-65257-invalid-var-decl-recovery.rs:16:5
    |
 LL |     mut var;
-   |     ^^^ help: missing keyword: `let mut`
+   |     ^^^
+   |
+help: missing keyword
+   |
+LL |     let mut var;
+   |     ~~~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-65257-invalid-var-decl-recovery.rs:20:33
diff --git a/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr b/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr
index 4961e8fc049..63131b474f0 100644
--- a/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr
+++ b/tests/ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.stderr
@@ -2,19 +2,25 @@ error: unexpected `...`
   --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:4:13
    |
 LL |     let Foo(...) = Foo(0);
-   |             ^^^
-   |             |
-   |             not a valid pattern
-   |             help: for a rest pattern, use `..` instead of `...`
+   |             ^^^ not a valid pattern
+   |
+help: for a rest pattern, use `..` instead of `...`
+   |
+LL -     let Foo(...) = Foo(0);
+LL +     let Foo(..) = Foo(0);
+   |
 
 error: unexpected `...`
   --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:5:13
    |
 LL |     let [_, ..., _] = [0, 1];
-   |             ^^^
-   |             |
-   |             not a valid pattern
-   |             help: for a rest pattern, use `..` instead of `...`
+   |             ^^^ not a valid pattern
+   |
+help: for a rest pattern, use `..` instead of `...`
+   |
+LL -     let [_, ..., _] = [0, 1];
+LL +     let [_, .., _] = [0, 1];
+   |
 
 error[E0308]: mismatched types
   --> $DIR/issue-70388-recover-dotdotdot-rest-pat.rs:6:33
diff --git a/tests/ui/parser/issues/issue-70388-without-witness.stderr b/tests/ui/parser/issues/issue-70388-without-witness.stderr
index b750ad4c626..ed78377607d 100644
--- a/tests/ui/parser/issues/issue-70388-without-witness.stderr
+++ b/tests/ui/parser/issues/issue-70388-without-witness.stderr
@@ -2,19 +2,25 @@ error: unexpected `...`
   --> $DIR/issue-70388-without-witness.rs:7:13
    |
 LL |     let Foo(...) = Foo(0);
-   |             ^^^
-   |             |
-   |             not a valid pattern
-   |             help: for a rest pattern, use `..` instead of `...`
+   |             ^^^ not a valid pattern
+   |
+help: for a rest pattern, use `..` instead of `...`
+   |
+LL -     let Foo(...) = Foo(0);
+LL +     let Foo(..) = Foo(0);
+   |
 
 error: unexpected `...`
   --> $DIR/issue-70388-without-witness.rs:8:13
    |
 LL |     let [_, ..., _] = [0, 1];
-   |             ^^^
-   |             |
-   |             not a valid pattern
-   |             help: for a rest pattern, use `..` instead of `...`
+   |             ^^^ not a valid pattern
+   |
+help: for a rest pattern, use `..` instead of `...`
+   |
+LL -     let [_, ..., _] = [0, 1];
+LL +     let [_, .., _] = [0, 1];
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr
index ec0af9a6caf..79c574ead61 100644
--- a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr
+++ b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr
@@ -17,7 +17,13 @@ error: unexpected lifetime `'static` in pattern
   --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:13
    |
 LL |     fn bar(&'static mur Self) {}
-   |             ^^^^^^^ help: remove the lifetime
+   |             ^^^^^^^
+   |
+help: remove the lifetime
+   |
+LL -     fn bar(&'static mur Self) {}
+LL +     fn bar(&mur Self) {}
+   |
 
 error: expected identifier, found keyword `Self`
   --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:25
diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
index 652aeff5dd4..2f8728bd78b 100644
--- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
+++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
@@ -2,24 +2,38 @@ error: lifetime must precede `mut`
   --> $DIR/issue-73568-lifetime-after-mut.rs:2:13
    |
 LL | fn x<'a>(x: &mut 'a i32){}
-   |             ^^^^^^^ help: place the lifetime before `mut`: `&'a mut`
+   |             ^^^^^^^
+   |
+help: place the lifetime before `mut`
+   |
+LL | fn x<'a>(x: &'a mut i32){}
+   |             ~~~~~~~
 
 error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a`
   --> $DIR/issue-73568-lifetime-after-mut.rs:14:13
    |
 LL | fn y<'a>(y: &mut 'a + Send) {
-   |             ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)`
+   |             ^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | fn y<'a>(y: &mut ('a + Send)) {
+   |                  +         +
 
 error: lifetime must precede `mut`
   --> $DIR/issue-73568-lifetime-after-mut.rs:6:22
    |
 LL |         fn w<$lt>(w: &mut $lt i32) {}
-   |                      ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut`
+   |                      ^^^^^^^^
 ...
 LL | mac!('a);
    | -------- in this macro invocation
    |
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: place the lifetime before `mut`
+   |
+LL |         fn w<$lt>(w: &$lt mut i32) {}
+   |                      ~~~~~~~~
 
 error[E0423]: expected value, found trait `Send`
   --> $DIR/issue-73568-lifetime-after-mut.rs:17:28
diff --git a/tests/ui/parser/issues/issue-89574.stderr b/tests/ui/parser/issues/issue-89574.stderr
index a0586d41e2e..aa5e66b18a9 100644
--- a/tests/ui/parser/issues/issue-89574.stderr
+++ b/tests/ui/parser/issues/issue-89574.stderr
@@ -8,7 +8,12 @@ error: missing type for `const` item
   --> $DIR/issue-89574.rs:2:22
    |
 LL |     const EMPTY_ARRAY = [];
-   |                      ^ help: provide a type for the item: `: <type>`
+   |                      ^
+   |
+help: provide a type for the item
+   |
+LL |     const EMPTY_ARRAY: <type> = [];
+   |                      ++++++++
 
 error[E0282]: type annotations needed
   --> $DIR/issue-89574.rs:2:25
diff --git a/tests/ui/parser/issues/issue-90993.stderr b/tests/ui/parser/issues/issue-90993.stderr
index ab6bce410e6..a18e93f1f1a 100644
--- a/tests/ui/parser/issues/issue-90993.stderr
+++ b/tests/ui/parser/issues/issue-90993.stderr
@@ -17,9 +17,13 @@ error: unexpected `=` after inclusive range
   --> $DIR/issue-90993.rs:2:5
    |
 LL |     ...=.
-   |     ^^^^ help: use `..=` instead
+   |     ^^^^
    |
    = note: inclusive ranges end with a single equals sign (`..=`)
+help: use `..=` instead
+   |
+LL |     ..=.
+   |     ~~~
 
 error: expected one of `-`, `;`, `}`, or path, found `.`
   --> $DIR/issue-90993.rs:2:9
diff --git a/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr
index c503bc3ccfc..c98b8fa1f1e 100644
--- a/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr
+++ b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr
@@ -2,7 +2,12 @@ error: `enum` and `struct` are mutually exclusive
   --> $DIR/issue-99625-enum-struct-mutually-exclusive.rs:3:5
    |
 LL | pub enum struct Range {
-   |     ^^^^^^^^^^^ help: replace `enum struct` with: `enum`
+   |     ^^^^^^^^^^^
+   |
+help: replace `enum struct` with
+   |
+LL | pub enum Range {
+   |     ~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr
index 72377fc379c..1ccf44a350d 100644
--- a/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr
+++ b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr
@@ -2,13 +2,23 @@ error: `const` and `let` are mutually exclusive
   --> $DIR/issue-99910-const-let-mutually-exclusive.rs:4:5
    |
 LL |     const let _FOO: i32 = 123;
-   |     ^^^^^^^^^ help: remove `let`: `const`
+   |     ^^^^^^^^^
+   |
+help: remove `let`
+   |
+LL |     const _FOO: i32 = 123;
+   |     ~~~~~
 
 error: `const` and `let` are mutually exclusive
   --> $DIR/issue-99910-const-let-mutually-exclusive.rs:6:5
    |
 LL |     let const _BAR: i32 = 123;
-   |     ^^^^^^^^^ help: remove `let`: `const`
+   |     ^^^^^^^^^
+   |
+help: remove `let`
+   |
+LL |     const _BAR: i32 = 123;
+   |     ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs
index 3fbac5fae23..a8a608c191a 100644
--- a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs
+++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs
@@ -2,4 +2,5 @@
 // Tests that we still emit an error after an item.
 
 fn main() { }
-; //~ ERROR expected item, found `;`
+;
+//~^ ERROR expected item, found `;`
diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr
index 2d7f540443d..aae5c1e1b22 100644
--- a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr
+++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr
@@ -2,9 +2,13 @@ error: expected item, found `;`
   --> $DIR/missing-main-issue-124935-semi-after-item.rs:5:1
    |
 LL | ;
-   | ^ help: remove this semicolon
+   | ^
    |
    = help: function declarations are not followed by a semicolon
+help: remove this semicolon
+   |
+LL - ;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr b/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr
index 5365b0a1f82..1ecf9912e9b 100644
--- a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr
+++ b/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr
@@ -18,7 +18,12 @@ error: missing type for `const` item
   --> $DIR/item-free-const-no-body-semantic-fail.rs:6:8
    |
 LL | const B;
-   |        ^ help: provide a type for the item: `: <type>`
+   |        ^
+   |
+help: provide a type for the item
+   |
+LL | const B: <type>;
+   |        ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr b/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr
index 1b61e430546..3af7c642468 100644
--- a/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr
+++ b/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr
@@ -34,13 +34,23 @@ error: missing type for `static` item
   --> $DIR/item-free-static-no-body-semantic-fail.rs:6:9
    |
 LL | static B;
-   |         ^ help: provide a type for the item: `: <type>`
+   |         ^
+   |
+help: provide a type for the item
+   |
+LL | static B: <type>;
+   |         ++++++++
 
 error: missing type for `static mut` item
   --> $DIR/item-free-static-no-body-semantic-fail.rs:10:13
    |
 LL | static mut D;
-   |             ^ help: provide a type for the item: `: <type>`
+   |             ^
+   |
+help: provide a type for the item
+   |
+LL | static mut D: <type>;
+   |             ++++++++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/parser/item-kw-case-mismatch.stderr b/tests/ui/parser/item-kw-case-mismatch.stderr
index ba59ea85363..0abc59e064a 100644
--- a/tests/ui/parser/item-kw-case-mismatch.stderr
+++ b/tests/ui/parser/item-kw-case-mismatch.stderr
@@ -2,85 +2,155 @@ error: keyword `use` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:7:1
    |
 LL | Use std::ptr::read;
-   | ^^^ help: write it in the correct case (notice the capitalization): `use`
+   | ^^^
+   |
+help: write it in the correct case (notice the capitalization difference)
+   |
+LL | use std::ptr::read;
+   | ~~~
 
 error: keyword `use` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:8:1
    |
 LL | USE std::ptr::write;
-   | ^^^ help: write it in the correct case: `use`
+   | ^^^
+   |
+help: write it in the correct case
+   |
+LL | use std::ptr::write;
+   | ~~~
 
 error: keyword `fn` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:10:7
    |
 LL | async Fn _a() {}
-   |       ^^ help: write it in the correct case (notice the capitalization): `fn`
+   |       ^^
+   |
+help: write it in the correct case (notice the capitalization difference)
+   |
+LL | async fn _a() {}
+   |       ~~
 
 error: keyword `fn` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:13:1
    |
 LL | Fn _b() {}
-   | ^^ help: write it in the correct case (notice the capitalization): `fn`
+   | ^^
+   |
+help: write it in the correct case (notice the capitalization difference)
+   |
+LL | fn _b() {}
+   | ~~
 
 error: keyword `async` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:16:1
    |
 LL | aSYNC fN _c() {}
-   | ^^^^^ help: write it in the correct case: `async`
+   | ^^^^^
+   |
+help: write it in the correct case
+   |
+LL | async fN _c() {}
+   | ~~~~~
 
 error: keyword `fn` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:16:7
    |
 LL | aSYNC fN _c() {}
-   |       ^^ help: write it in the correct case: `fn`
+   |       ^^
+   |
+help: write it in the correct case
+   |
+LL | aSYNC fn _c() {}
+   |       ~~
 
 error: keyword `async` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:20:1
    |
 LL | Async fn _d() {}
-   | ^^^^^ help: write it in the correct case: `async`
+   | ^^^^^
+   |
+help: write it in the correct case
+   |
+LL | async fn _d() {}
+   | ~~~~~
 
 error: keyword `const` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:23:1
    |
 LL | CONST UNSAFE FN _e() {}
-   | ^^^^^ help: write it in the correct case: `const`
+   | ^^^^^
+   |
+help: write it in the correct case
+   |
+LL | const UNSAFE FN _e() {}
+   | ~~~~~
 
 error: keyword `unsafe` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:23:7
    |
 LL | CONST UNSAFE FN _e() {}
-   |       ^^^^^^ help: write it in the correct case: `unsafe`
+   |       ^^^^^^
+   |
+help: write it in the correct case
+   |
+LL | CONST unsafe FN _e() {}
+   |       ~~~~~~
 
 error: keyword `fn` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:23:14
    |
 LL | CONST UNSAFE FN _e() {}
-   |              ^^ help: write it in the correct case: `fn`
+   |              ^^
+   |
+help: write it in the correct case
+   |
+LL | CONST UNSAFE fn _e() {}
+   |              ~~
 
 error: keyword `unsafe` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:28:1
    |
 LL | unSAFE EXTern fn _f() {}
-   | ^^^^^^ help: write it in the correct case: `unsafe`
+   | ^^^^^^
+   |
+help: write it in the correct case
+   |
+LL | unsafe EXTern fn _f() {}
+   | ~~~~~~
 
 error: keyword `extern` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:28:8
    |
 LL | unSAFE EXTern fn _f() {}
-   |        ^^^^^^ help: write it in the correct case: `extern`
+   |        ^^^^^^
+   |
+help: write it in the correct case
+   |
+LL | unSAFE extern fn _f() {}
+   |        ~~~~~~
 
 error: keyword `extern` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:32:1
    |
 LL | EXTERN "C" FN _g() {}
-   | ^^^^^^ help: write it in the correct case: `extern`
+   | ^^^^^^
+   |
+help: write it in the correct case
+   |
+LL | extern "C" FN _g() {}
+   | ~~~~~~
 
 error: keyword `fn` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:32:12
    |
 LL | EXTERN "C" FN _g() {}
-   |            ^^ help: write it in the correct case: `fn`
+   |            ^^
+   |
+help: write it in the correct case
+   |
+LL | EXTERN "C" fn _g() {}
+   |            ~~
 
 error: aborting due to 14 previous errors
 
diff --git a/tests/ui/parser/label-after-block-like.stderr b/tests/ui/parser/label-after-block-like.stderr
index 8ff50b124b3..be8c679d8ce 100644
--- a/tests/ui/parser/label-after-block-like.stderr
+++ b/tests/ui/parser/label-after-block-like.stderr
@@ -2,12 +2,15 @@ error: labeled expression must be followed by `:`
   --> $DIR/label-after-block-like.rs:2:20
    |
 LL |     if let () = () 'a {}
-   |                    ---^^
-   |                    | |
-   |                    | help: add `:` after the label
+   |                    --^^^
+   |                    |
    |                    the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     if let () = () 'a: {}
+   |                      +
 
 error: expected `{`, found `'a`
   --> $DIR/label-after-block-like.rs:2:20
@@ -29,12 +32,15 @@ error: labeled expression must be followed by `:`
   --> $DIR/label-after-block-like.rs:8:13
    |
 LL |     if true 'a {}
-   |             ---^^
-   |             | |
-   |             | help: add `:` after the label
+   |             --^^^
+   |             |
    |             the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     if true 'a: {}
+   |               +
 
 error: expected `{`, found `'a`
   --> $DIR/label-after-block-like.rs:8:13
@@ -56,12 +62,15 @@ error: labeled expression must be followed by `:`
   --> $DIR/label-after-block-like.rs:14:10
    |
 LL |     loop 'a {}
-   |          ---^^
-   |          | |
-   |          | help: add `:` after the label
+   |          --^^^
+   |          |
    |          the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     loop 'a: {}
+   |            +
 
 error: expected `{`, found `'a`
   --> $DIR/label-after-block-like.rs:14:10
@@ -80,12 +89,15 @@ error: labeled expression must be followed by `:`
   --> $DIR/label-after-block-like.rs:20:16
    |
 LL |     while true 'a {}
-   |                ---^^
-   |                | |
-   |                | help: add `:` after the label
+   |                --^^^
+   |                |
    |                the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     while true 'a: {}
+   |                  +
 
 error: expected `{`, found `'a`
   --> $DIR/label-after-block-like.rs:20:16
@@ -105,12 +117,15 @@ error: labeled expression must be followed by `:`
   --> $DIR/label-after-block-like.rs:26:23
    |
 LL |     while let () = () 'a {}
-   |                       ---^^
-   |                       | |
-   |                       | help: add `:` after the label
+   |                       --^^^
+   |                       |
    |                       the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     while let () = () 'a: {}
+   |                         +
 
 error: expected `{`, found `'a`
   --> $DIR/label-after-block-like.rs:26:23
@@ -130,12 +145,15 @@ error: labeled expression must be followed by `:`
   --> $DIR/label-after-block-like.rs:32:19
    |
 LL |     for _ in 0..0 'a {}
-   |                   ---^^
-   |                   | |
-   |                   | help: add `:` after the label
+   |                   --^^^
+   |                   |
    |                   the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     for _ in 0..0 'a: {}
+   |                     +
 
 error: expected `{`, found `'a`
   --> $DIR/label-after-block-like.rs:32:19
@@ -152,12 +170,15 @@ error: labeled expression must be followed by `:`
   --> $DIR/label-after-block-like.rs:38:12
    |
 LL |     unsafe 'a {}
-   |            ---^^
-   |            | |
-   |            | help: add `:` after the label
+   |            --^^^
+   |            |
    |            the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     unsafe 'a: {}
+   |              +
 
 error: expected `{`, found `'a`
   --> $DIR/label-after-block-like.rs:38:12
diff --git a/tests/ui/parser/labeled-no-colon-expr.stderr b/tests/ui/parser/labeled-no-colon-expr.stderr
index 4d61d9c1403..24783192815 100644
--- a/tests/ui/parser/labeled-no-colon-expr.stderr
+++ b/tests/ui/parser/labeled-no-colon-expr.stderr
@@ -2,45 +2,57 @@ error: labeled expression must be followed by `:`
   --> $DIR/labeled-no-colon-expr.rs:2:5
    |
 LL |     'l0 while false {}
-   |     ----^^^^^^^^^^^^^^
-   |     |  |
-   |     |  help: add `:` after the label
+   |     ---^^^^^^^^^^^^^^^
+   |     |
    |     the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     'l0: while false {}
+   |        +
 
 error: labeled expression must be followed by `:`
   --> $DIR/labeled-no-colon-expr.rs:3:5
    |
 LL |     'l1 for _ in 0..1 {}
-   |     ----^^^^^^^^^^^^^^^^
-   |     |  |
-   |     |  help: add `:` after the label
+   |     ---^^^^^^^^^^^^^^^^^
+   |     |
    |     the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     'l1: for _ in 0..1 {}
+   |        +
 
 error: labeled expression must be followed by `:`
   --> $DIR/labeled-no-colon-expr.rs:4:5
    |
 LL |     'l2 loop {}
-   |     ----^^^^^^^
-   |     |  |
-   |     |  help: add `:` after the label
+   |     ---^^^^^^^^
+   |     |
    |     the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     'l2: loop {}
+   |        +
 
 error: labeled expression must be followed by `:`
   --> $DIR/labeled-no-colon-expr.rs:5:5
    |
 LL |     'l3 {}
-   |     ----^^
-   |     |  |
-   |     |  help: add `:` after the label
+   |     ---^^^
+   |     |
    |     the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     'l3: {}
+   |        +
 
 error: expected `while`, `for`, `loop` or `{` after a label
   --> $DIR/labeled-no-colon-expr.rs:6:9
@@ -58,12 +70,15 @@ error: labeled expression must be followed by `:`
   --> $DIR/labeled-no-colon-expr.rs:6:9
    |
 LL |     'l4 0;
-   |     ----^
-   |     |  |
-   |     |  help: add `:` after the label
+   |     --- ^
+   |     |
    |     the label
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |     'l4: 0;
+   |        +
 
 error: cannot use a `block` macro fragment here
   --> $DIR/labeled-no-colon-expr.rs:11:17
@@ -86,14 +101,16 @@ error: labeled expression must be followed by `:`
   --> $DIR/labeled-no-colon-expr.rs:14:8
    |
 LL |             'l5 $b;
-   |             ---- help: add `:` after the label
-   |             |
-   |             the label
+   |             --- the label
 ...
 LL |     m!({});
    |        ^^
    |
    = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+help: add `:` after the label
+   |
+LL |             'l5: $b;
+   |                +
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/parser/let-binop.stderr b/tests/ui/parser/let-binop.stderr
index dd33e9157cf..50ef14793cd 100644
--- a/tests/ui/parser/let-binop.stderr
+++ b/tests/ui/parser/let-binop.stderr
@@ -2,25 +2,40 @@ error: can't reassign to an uninitialized variable
   --> $DIR/let-binop.rs:4:15
    |
 LL |     let a: i8 *= 1;
-   |               ^^ help: initialize the variable
+   |               ^^
    |
    = help: if you meant to overwrite, remove the `let` binding
+help: initialize the variable
+   |
+LL -     let a: i8 *= 1;
+LL +     let a: i8 = 1;
+   |
 
 error: can't reassign to an uninitialized variable
   --> $DIR/let-binop.rs:6:11
    |
 LL |     let b += 1;
-   |           ^^ help: initialize the variable
+   |           ^^
    |
    = help: if you meant to overwrite, remove the `let` binding
+help: initialize the variable
+   |
+LL -     let b += 1;
+LL +     let b = 1;
+   |
 
 error: can't reassign to an uninitialized variable
   --> $DIR/let-binop.rs:8:11
    |
 LL |     let c *= 1;
-   |           ^^ help: initialize the variable
+   |           ^^
    |
    = help: if you meant to overwrite, remove the `let` binding
+help: initialize the variable
+   |
+LL -     let c *= 1;
+LL +     let c = 1;
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/lifetime-in-pattern-recover.stderr b/tests/ui/parser/lifetime-in-pattern-recover.stderr
index 4bf7f57bfb5..d0644da1dd1 100644
--- a/tests/ui/parser/lifetime-in-pattern-recover.stderr
+++ b/tests/ui/parser/lifetime-in-pattern-recover.stderr
@@ -2,13 +2,25 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/lifetime-in-pattern-recover.rs:2:10
    |
 LL |     let &'a x = &0;
-   |          ^^ help: remove the lifetime
+   |          ^^
+   |
+help: remove the lifetime
+   |
+LL -     let &'a x = &0;
+LL +     let &x = &0;
+   |
 
 error: unexpected lifetime `'a` in pattern
   --> $DIR/lifetime-in-pattern-recover.rs:3:10
    |
 LL |     let &'a mut y = &mut 0;
-   |          ^^ help: remove the lifetime
+   |          ^^
+   |
+help: remove the lifetime
+   |
+LL -     let &'a mut y = &mut 0;
+LL +     let &mut y = &mut 0;
+   |
 
 error[E0308]: mismatched types
   --> $DIR/lifetime-in-pattern-recover.rs:5:33
diff --git a/tests/ui/parser/lifetime-in-pattern.stderr b/tests/ui/parser/lifetime-in-pattern.stderr
index a1d721e746a..55f9e56a429 100644
--- a/tests/ui/parser/lifetime-in-pattern.stderr
+++ b/tests/ui/parser/lifetime-in-pattern.stderr
@@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/lifetime-in-pattern.rs:1:10
    |
 LL | fn test(&'a str) {
-   |          ^^ help: remove the lifetime
+   |          ^^
+   |
+help: remove the lifetime
+   |
+LL - fn test(&'a str) {
+LL + fn test(&str) {
+   |
 
 error: expected one of `:`, `@`, or `|`, found `)`
   --> $DIR/lifetime-in-pattern.rs:1:16
diff --git a/tests/ui/parser/macro/pub-item-macro.stderr b/tests/ui/parser/macro/pub-item-macro.stderr
index 9a2fffcced5..14f0b0908d1 100644
--- a/tests/ui/parser/macro/pub-item-macro.stderr
+++ b/tests/ui/parser/macro/pub-item-macro.stderr
@@ -2,13 +2,18 @@ error: can't qualify macro invocation with `pub`
   --> $DIR/pub-item-macro.rs:10:5
    |
 LL |     pub priv_x!();
-   |     ^^^ help: remove the visibility
+   |     ^^^
 ...
 LL |     pub_x!();
    |     -------- in this macro invocation
    |
    = help: try adjusting the macro to put `pub` inside the invocation
    = note: this error originates in the macro `pub_x` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: remove the visibility
+   |
+LL -     pub priv_x!();
+LL +      priv_x!();
+   |
 
 error[E0603]: static `x` is private
   --> $DIR/pub-item-macro.rs:20:23
diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr
index a3f7e32c177..53cf3480dbf 100644
--- a/tests/ui/parser/match-arm-without-body.stderr
+++ b/tests/ui/parser/match-arm-without-body.stderr
@@ -56,7 +56,12 @@ error: expected `,` following `match` arm
   --> $DIR/match-arm-without-body.rs:66:15
    |
 LL |         pat!()
-   |               ^ help: missing a comma here to end this `match` arm: `,`
+   |               ^
+   |
+help: missing a comma here to end this `match` arm
+   |
+LL |         pat!(),
+   |               +
 
 error: `match` arm with no body
   --> $DIR/match-arm-without-body.rs:7:9
diff --git a/tests/ui/parser/match-arm-without-braces.stderr b/tests/ui/parser/match-arm-without-braces.stderr
index ee1c8e562fc..4a4a154d860 100644
--- a/tests/ui/parser/match-arm-without-braces.stderr
+++ b/tests/ui/parser/match-arm-without-braces.stderr
@@ -60,7 +60,12 @@ error: expected `,` following `match` arm
   --> $DIR/match-arm-without-braces.rs:48:29
    |
 LL |         Some(Val::Foo) => 17
-   |                             ^ help: missing a comma here to end this `match` arm: `,`
+   |                             ^
+   |
+help: missing a comma here to end this `match` arm
+   |
+LL |         Some(Val::Foo) => 17,
+   |                             +
 
 error: `match` arm body without braces
   --> $DIR/match-arm-without-braces.rs:53:11
diff --git a/tests/ui/parser/mut-patterns.stderr b/tests/ui/parser/mut-patterns.stderr
index 6559cf09cdf..f4f11b88d36 100644
--- a/tests/ui/parser/mut-patterns.stderr
+++ b/tests/ui/parser/mut-patterns.stderr
@@ -2,53 +2,87 @@ error: `mut` must be followed by a named binding
   --> $DIR/mut-patterns.rs:9:9
    |
 LL |     let mut _ = 0;
-   |         ^^^^ help: remove the `mut` prefix
+   |         ^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: remove the `mut` prefix
+   |
+LL -     let mut _ = 0;
+LL +     let _ = 0;
+   |
 
 error: `mut` must be followed by a named binding
   --> $DIR/mut-patterns.rs:10:9
    |
 LL |     let mut (_, _) = (0, 0);
-   |         ^^^^ help: remove the `mut` prefix
+   |         ^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: remove the `mut` prefix
+   |
+LL -     let mut (_, _) = (0, 0);
+LL +     let (_, _) = (0, 0);
+   |
 
 error: `mut` must be attached to each individual binding
   --> $DIR/mut-patterns.rs:12:9
    |
 LL |     let mut (x @ y) = 0;
-   |         ^^^^^^^^^^^ help: add `mut` to each binding: `(mut x @ mut y)`
+   |         ^^^^^^^^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: add `mut` to each binding
+   |
+LL |     let (mut x @ mut y) = 0;
+   |         ~~~~~~~~~~~~~~~
 
 error: `mut` on a binding may not be repeated
   --> $DIR/mut-patterns.rs:14:13
    |
 LL |     let mut mut x = 0;
-   |             ^^^ help: remove the additional `mut`s
+   |             ^^^
+   |
+help: remove the additional `mut`s
+   |
+LL -     let mut mut x = 0;
+LL +     let mut  x = 0;
+   |
 
 error: `mut` must be attached to each individual binding
   --> $DIR/mut-patterns.rs:19:9
    |
 LL |     let mut Foo { x: x } = Foo { x: 3 };
-   |         ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }`
+   |         ^^^^^^^^^^^^^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: add `mut` to each binding
+   |
+LL |     let Foo { x: mut x } = Foo { x: 3 };
+   |         ~~~~~~~~~~~~~~~~
 
 error: `mut` must be attached to each individual binding
   --> $DIR/mut-patterns.rs:23:9
    |
 LL |     let mut Foo { x } = Foo { x: 3 };
-   |         ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }`
+   |         ^^^^^^^^^^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: add `mut` to each binding
+   |
+LL |     let Foo { mut x } = Foo { x: 3 };
+   |         ~~~~~~~~~~~~~
 
 error: `mut` on a binding may not be repeated
   --> $DIR/mut-patterns.rs:28:13
    |
 LL |     let mut mut yield(become, await) = r#yield(0, 0);
-   |             ^^^ help: remove the additional `mut`s
+   |             ^^^
+   |
+help: remove the additional `mut`s
+   |
+LL -     let mut mut yield(become, await) = r#yield(0, 0);
+LL +     let mut  yield(become, await) = r#yield(0, 0);
+   |
 
 error: expected identifier, found reserved keyword `yield`
   --> $DIR/mut-patterns.rs:28:17
@@ -87,17 +121,26 @@ error: `mut` must be followed by a named binding
   --> $DIR/mut-patterns.rs:28:9
    |
 LL |     let mut mut yield(become, await) = r#yield(0, 0);
-   |         ^^^^^^^^ help: remove the `mut` prefix
+   |         ^^^^^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: remove the `mut` prefix
+   |
+LL -     let mut mut yield(become, await) = r#yield(0, 0);
+LL +     let yield(become, await) = r#yield(0, 0);
+   |
 
 error: `mut` must be attached to each individual binding
   --> $DIR/mut-patterns.rs:37:9
    |
 LL |     let mut W(mut a, W(b, W(ref c, W(d, B { box f }))))
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: add `mut` to each binding
+   |
+LL |     let W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: expected identifier, found `x`
   --> $DIR/mut-patterns.rs:44:21
diff --git a/tests/ui/parser/not-a-pred.stderr b/tests/ui/parser/not-a-pred.stderr
index bcc64a687fd..6f6a332cb81 100644
--- a/tests/ui/parser/not-a-pred.stderr
+++ b/tests/ui/parser/not-a-pred.stderr
@@ -2,7 +2,12 @@ error: return types are denoted using `->`
   --> $DIR/not-a-pred.rs:1:26
    |
 LL | fn f(a: isize, b: isize) : lt(a, b) { }
-   |                          ^ help: use `->` instead
+   |                          ^
+   |
+help: use `->` instead
+   |
+LL | fn f(a: isize, b: isize) -> lt(a, b) { }
+   |                          ~~
 
 error[E0573]: expected type, found function `lt`
   --> $DIR/not-a-pred.rs:1:28
diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/pat-recover-wildcards.stderr
index 2b0c9bbc5be..e36ff237bb0 100644
--- a/tests/ui/parser/pat-recover-wildcards.stderr
+++ b/tests/ui/parser/pat-recover-wildcards.stderr
@@ -32,9 +32,14 @@ error[E0586]: inclusive range with no end
   --> $DIR/pat-recover-wildcards.rs:35:10
    |
 LL |         0..._ => ()
-   |          ^^^ help: use `..` instead
+   |          ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -         0..._ => ()
+LL +         0.._ => ()
+   |
 
 error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
   --> $DIR/pat-recover-wildcards.rs:35:13
diff --git a/tests/ui/parser/pub-method-macro.stderr b/tests/ui/parser/pub-method-macro.stderr
index 35cbf423079..2e2c30dc6ad 100644
--- a/tests/ui/parser/pub-method-macro.stderr
+++ b/tests/ui/parser/pub-method-macro.stderr
@@ -2,9 +2,14 @@ error: can't qualify macro invocation with `pub`
   --> $DIR/pub-method-macro.rs:17:9
    |
 LL |         pub defn!(f);
-   |         ^^^ help: remove the visibility
+   |         ^^^
    |
    = help: try adjusting the macro to put `pub` inside the invocation
+help: remove the visibility
+   |
+LL -         pub defn!(f);
+LL +          defn!(f);
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/range-inclusive-extra-equals.stderr b/tests/ui/parser/range-inclusive-extra-equals.stderr
index 83df719dd3c..a573cdf950c 100644
--- a/tests/ui/parser/range-inclusive-extra-equals.stderr
+++ b/tests/ui/parser/range-inclusive-extra-equals.stderr
@@ -2,9 +2,13 @@ error: unexpected `=` after inclusive range
   --> $DIR/range-inclusive-extra-equals.rs:7:13
    |
 LL |     if let 1..==3 = 1 {}
-   |             ^^^^ help: use `..=` instead
+   |             ^^^^
    |
    = note: inclusive ranges end with a single equals sign (`..=`)
+help: use `..=` instead
+   |
+LL |     if let 1..=3 = 1 {}
+   |             ~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/range_inclusive.stderr b/tests/ui/parser/range_inclusive.stderr
index 0fd7f28db31..014f95bcd84 100644
--- a/tests/ui/parser/range_inclusive.stderr
+++ b/tests/ui/parser/range_inclusive.stderr
@@ -2,9 +2,14 @@ error[E0586]: inclusive range with no end
   --> $DIR/range_inclusive.rs:5:15
    |
 LL |     for _ in 1..= {}
-   |               ^^^ help: use `..` instead
+   |               ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     for _ in 1..= {}
+LL +     for _ in 1.. {}
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
index 7012096b644..8e5b76163ad 100644
--- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
@@ -5,7 +5,12 @@ LL | type T0 = const fn();
    |           -----^^^^^
    |           |
    |           `const` because of this
-   |           help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - type T0 = const fn();
+LL + type T0 =  fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:4:11
@@ -14,7 +19,12 @@ LL | type T1 = const extern "C" fn();
    |           -----^^^^^^^^^^^^^^^^
    |           |
    |           `const` because of this
-   |           help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - type T1 = const extern "C" fn();
+LL + type T1 =  extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:5:11
@@ -23,7 +33,12 @@ LL | type T2 = const unsafe extern fn();
    |           -----^^^^^^^^^^^^^^^^^^^
    |           |
    |           `const` because of this
-   |           help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - type T2 = const unsafe extern fn();
+LL + type T2 =  unsafe extern fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:6:11
@@ -32,7 +47,12 @@ LL | type T3 = async fn();
    |           -----^^^^^
    |           |
    |           `async` because of this
-   |           help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - type T3 = async fn();
+LL + type T3 =  fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:7:11
@@ -41,7 +61,12 @@ LL | type T4 = async extern fn();
    |           -----^^^^^^^^^^^^
    |           |
    |           `async` because of this
-   |           help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - type T4 = async extern fn();
+LL + type T4 =  extern fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:8:11
@@ -50,7 +75,12 @@ LL | type T5 = async unsafe extern "C" fn();
    |           -----^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           `async` because of this
-   |           help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - type T5 = async unsafe extern "C" fn();
+LL + type T5 =  unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:9:11
@@ -59,7 +89,12 @@ LL | type T6 = const async unsafe extern "C" fn();
    |           -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           `const` because of this
-   |           help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - type T6 = const async unsafe extern "C" fn();
+LL + type T6 =  async unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:9:11
@@ -68,7 +103,12 @@ LL | type T6 = const async unsafe extern "C" fn();
    |           ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
    |                 |
    |                 `async` because of this
-   |                 help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - type T6 = const async unsafe extern "C" fn();
+LL + type T6 = const  unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:13:12
@@ -77,7 +117,12 @@ LL | type FT0 = for<'a> const fn();
    |            ^^^^^^^^-----^^^^^
    |                    |
    |                    `const` because of this
-   |                    help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - type FT0 = for<'a> const fn();
+LL + type FT0 = for<'a>  fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:14:12
@@ -86,7 +131,12 @@ LL | type FT1 = for<'a> const extern "C" fn();
    |            ^^^^^^^^-----^^^^^^^^^^^^^^^^
    |                    |
    |                    `const` because of this
-   |                    help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - type FT1 = for<'a> const extern "C" fn();
+LL + type FT1 = for<'a>  extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:15:12
@@ -95,7 +145,12 @@ LL | type FT2 = for<'a> const unsafe extern fn();
    |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^
    |                    |
    |                    `const` because of this
-   |                    help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - type FT2 = for<'a> const unsafe extern fn();
+LL + type FT2 = for<'a>  unsafe extern fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:16:12
@@ -104,7 +159,12 @@ LL | type FT3 = for<'a> async fn();
    |            ^^^^^^^^-----^^^^^
    |                    |
    |                    `async` because of this
-   |                    help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - type FT3 = for<'a> async fn();
+LL + type FT3 = for<'a>  fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:17:12
@@ -113,7 +173,12 @@ LL | type FT4 = for<'a> async extern fn();
    |            ^^^^^^^^-----^^^^^^^^^^^^
    |                    |
    |                    `async` because of this
-   |                    help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - type FT4 = for<'a> async extern fn();
+LL + type FT4 = for<'a>  extern fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:18:12
@@ -122,7 +187,12 @@ LL | type FT5 = for<'a> async unsafe extern "C" fn();
    |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
    |                    |
    |                    `async` because of this
-   |                    help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - type FT5 = for<'a> async unsafe extern "C" fn();
+LL + type FT5 = for<'a>  unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:19:12
@@ -131,7 +201,12 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn();
    |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                    |
    |                    `const` because of this
-   |                    help: remove the `const` qualifier
+   |
+help: remove the `const` qualifier
+   |
+LL - type FT6 = for<'a> const async unsafe extern "C" fn();
+LL + type FT6 = for<'a>  async unsafe extern "C" fn();
+   |
 
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:19:12
@@ -140,7 +215,12 @@ LL | type FT6 = for<'a> const async unsafe extern "C" fn();
    |            ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
    |                          |
    |                          `async` because of this
-   |                          help: remove the `async` qualifier
+   |
+help: remove the `async` qualifier
+   |
+LL - type FT6 = for<'a> const async unsafe extern "C" fn();
+LL + type FT6 = for<'a> const  unsafe extern "C" fn();
+   |
 
 error[E0308]: mismatched types
   --> $DIR/recover-const-async-fn-ptr.rs:24:33
diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr
index 2b56498c50d..68d57f20bd7 100644
--- a/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr
+++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr
@@ -1,11 +1,14 @@
 error: unmatched angle bracket
   --> $DIR/recover-field-extra-angle-brackets-in-struct-with-a-field.rs:2:25
    |
-LL |       next: Option<String>>
-   |  _________________________^
-LL | |
-LL | | }
-   | |_ help: remove extra angle bracket
+LL |     next: Option<String>>
+   |                         ^
+   |
+help: remove extra angle bracket
+   |
+LL -     next: Option<String>>
+LL +     next: Option<String>
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr b/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr
index 628626926a7..45af6313391 100644
--- a/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr
+++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr
@@ -2,7 +2,13 @@ error: unmatched angle bracket
   --> $DIR/recover-field-extra-angle-brackets.rs:5:19
    |
 LL |     first: Vec<u8>>,
-   |                   ^ help: remove extra angle bracket
+   |                   ^
+   |
+help: remove extra angle bracket
+   |
+LL -     first: Vec<u8>>,
+LL +     first: Vec<u8>,
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr
index e29b6c1c666..b8e91c2344a 100644
--- a/tests/ui/parser/recover/recover-range-pats.stderr
+++ b/tests/ui/parser/recover/recover-range-pats.stderr
@@ -2,196 +2,330 @@ error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:20:12
    |
 LL |     if let .0..Y = 0 {}
-   |            ^^ help: must have an integer part: `0.0`
+   |            ^^
+   |
+help: must have an integer part
+   |
+LL |     if let 0.0..Y = 0 {}
+   |            +
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:22:16
    |
 LL |     if let X.. .0 = 0 {}
-   |                ^^ help: must have an integer part: `0.0`
+   |                ^^
+   |
+help: must have an integer part
+   |
+LL |     if let X.. 0.0 = 0 {}
+   |                +
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:33:12
    |
 LL |     if let .0..=Y = 0 {}
-   |            ^^ help: must have an integer part: `0.0`
+   |            ^^
+   |
+help: must have an integer part
+   |
+LL |     if let 0.0..=Y = 0 {}
+   |            +
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:35:16
    |
 LL |     if let X..=.0 = 0 {}
-   |                ^^ help: must have an integer part: `0.0`
+   |                ^^
+   |
+help: must have an integer part
+   |
+LL |     if let X..=0.0 = 0 {}
+   |                +
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:58:12
    |
 LL |     if let .0...Y = 0 {}
-   |            ^^ help: must have an integer part: `0.0`
+   |            ^^
+   |
+help: must have an integer part
+   |
+LL |     if let 0.0...Y = 0 {}
+   |            +
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:62:17
    |
 LL |     if let X... .0 = 0 {}
-   |                 ^^ help: must have an integer part: `0.0`
+   |                 ^^
+   |
+help: must have an integer part
+   |
+LL |     if let X... 0.0 = 0 {}
+   |                 +
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:73:12
    |
 LL |     if let .0.. = 0 {}
-   |            ^^ help: must have an integer part: `0.0`
+   |            ^^
+   |
+help: must have an integer part
+   |
+LL |     if let 0.0.. = 0 {}
+   |            +
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:79:13
    |
 LL |     if let 0..= = 0 {}
-   |             ^^^ help: use `..` instead
+   |             ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let 0..= = 0 {}
+LL +     if let 0.. = 0 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:80:13
    |
 LL |     if let X..= = 0 {}
-   |             ^^^ help: use `..` instead
+   |             ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let X..= = 0 {}
+LL +     if let X.. = 0 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:81:16
    |
 LL |     if let true..= = 0 {}
-   |                ^^^ help: use `..` instead
+   |                ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let true..= = 0 {}
+LL +     if let true.. = 0 {}
+   |
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:83:12
    |
 LL |     if let .0..= = 0 {}
-   |            ^^ help: must have an integer part: `0.0`
+   |            ^^
+   |
+help: must have an integer part
+   |
+LL |     if let 0.0..= = 0 {}
+   |            +
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:83:14
    |
 LL |     if let .0..= = 0 {}
-   |              ^^^ help: use `..` instead
+   |              ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let .0..= = 0 {}
+LL +     if let .0.. = 0 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:89:13
    |
 LL |     if let 0... = 0 {}
-   |             ^^^ help: use `..` instead
+   |             ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let 0... = 0 {}
+LL +     if let 0.. = 0 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:90:13
    |
 LL |     if let X... = 0 {}
-   |             ^^^ help: use `..` instead
+   |             ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let X... = 0 {}
+LL +     if let X.. = 0 {}
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:91:16
    |
 LL |     if let true... = 0 {}
-   |                ^^^ help: use `..` instead
+   |                ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let true... = 0 {}
+LL +     if let true.. = 0 {}
+   |
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:93:12
    |
 LL |     if let .0... = 0 {}
-   |            ^^ help: must have an integer part: `0.0`
+   |            ^^
+   |
+help: must have an integer part
+   |
+LL |     if let 0.0... = 0 {}
+   |            +
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:93:14
    |
 LL |     if let .0... = 0 {}
-   |              ^^^ help: use `..` instead
+   |              ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     if let .0... = 0 {}
+LL +     if let .0.. = 0 {}
+   |
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:103:15
    |
 LL |     if let .. .0 = 0 {}
-   |               ^^ help: must have an integer part: `0.0`
+   |               ^^
+   |
+help: must have an integer part
+   |
+LL |     if let .. 0.0 = 0 {}
+   |               +
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:113:15
    |
 LL |     if let ..=.0 = 0 {}
-   |               ^^ help: must have an integer part: `0.0`
+   |               ^^
+   |
+help: must have an integer part
+   |
+LL |     if let ..=0.0 = 0 {}
+   |               +
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/recover-range-pats.rs:119:12
    |
 LL |     if let ...3 = 0 {}
-   |            ^^^ help: use `..=` instead
+   |            ^^^
+   |
+help: use `..=` instead
+   |
+LL |     if let ..=3 = 0 {}
+   |            ~~~
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/recover-range-pats.rs:121:12
    |
 LL |     if let ...Y = 0 {}
-   |            ^^^ help: use `..=` instead
+   |            ^^^
+   |
+help: use `..=` instead
+   |
+LL |     if let ..=Y = 0 {}
+   |            ~~~
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/recover-range-pats.rs:123:12
    |
 LL |     if let ...true = 0 {}
-   |            ^^^ help: use `..=` instead
+   |            ^^^
+   |
+help: use `..=` instead
+   |
+LL |     if let ..=true = 0 {}
+   |            ~~~
 
 error: float literals must have an integer part
   --> $DIR/recover-range-pats.rs:126:15
    |
 LL |     if let ....3 = 0 {}
-   |               ^^ help: must have an integer part: `0.3`
+   |               ^^
+   |
+help: must have an integer part
+   |
+LL |     if let ...0.3 = 0 {}
+   |               +
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/recover-range-pats.rs:126:12
    |
 LL |     if let ....3 = 0 {}
-   |            ^^^ help: use `..=` instead
+   |            ^^^
+   |
+help: use `..=` instead
+   |
+LL |     if let ..=.3 = 0 {}
+   |            ~~~
 
 error: range-to patterns with `...` are not allowed
   --> $DIR/recover-range-pats.rs:152:17
    |
 LL |             let ...$e;
-   |                 ^^^ help: use `..=` instead
+   |                 ^^^
 ...
 LL |     mac!(0);
    |     ------- in this macro invocation
    |
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `..=` instead
+   |
+LL |             let ..=$e;
+   |                 ~~~
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:159:19
    |
 LL |             let $e...;
-   |                   ^^^ help: use `..` instead
+   |                   ^^^
 ...
 LL |     mac!(0);
    |     ------- in this macro invocation
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `..` instead
+   |
+LL -             let $e...;
+LL +             let $e..;
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/recover-range-pats.rs:161:19
    |
 LL |             let $e..=;
-   |                   ^^^ help: use `..` instead
+   |                   ^^^
 ...
 LL |     mac!(0);
    |     ------- in this macro invocation
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `..` instead
+   |
+LL -             let $e..=;
+LL +             let $e..;
+   |
 
 error: `...` range patterns are deprecated
   --> $DIR/recover-range-pats.rs:40:13
diff --git a/tests/ui/parser/recover/recover-ref-dyn-mut.stderr b/tests/ui/parser/recover/recover-ref-dyn-mut.stderr
index c048c8ea1b0..bb0f0b0214c 100644
--- a/tests/ui/parser/recover/recover-ref-dyn-mut.stderr
+++ b/tests/ui/parser/recover/recover-ref-dyn-mut.stderr
@@ -2,7 +2,12 @@ error: `mut` must precede `dyn`
   --> $DIR/recover-ref-dyn-mut.rs:5:12
    |
 LL |     let r: &dyn mut Trait;
-   |            ^^^^^^^^ help: place `mut` before `dyn`: `&mut dyn`
+   |            ^^^^^^^^
+   |
+help: place `mut` before `dyn`
+   |
+LL |     let r: &mut dyn Trait;
+   |            ~~~~~~~~
 
 error[E0405]: cannot find trait `Trait` in this scope
   --> $DIR/recover-ref-dyn-mut.rs:5:21
diff --git a/tests/ui/parser/recover/recover-unticked-labels.stderr b/tests/ui/parser/recover/recover-unticked-labels.stderr
index fbd108ca613..5cf463677af 100644
--- a/tests/ui/parser/recover/recover-unticked-labels.stderr
+++ b/tests/ui/parser/recover/recover-unticked-labels.stderr
@@ -2,17 +2,23 @@ error: expected a label, found an identifier
   --> $DIR/recover-unticked-labels.rs:5:26
    |
 LL |     'label: loop { break label 0 };
-   |                          -^^^^
-   |                          |
-   |                          help: labels start with a tick
+   |                          ^^^^^
+   |
+help: labels start with a tick
+   |
+LL |     'label: loop { break 'label 0 };
+   |                          +
 
 error: expected a label, found an identifier
   --> $DIR/recover-unticked-labels.rs:6:29
    |
 LL |     'label: loop { continue label };
-   |                             -^^^^
-   |                             |
-   |                             help: labels start with a tick
+   |                             ^^^^^
+   |
+help: labels start with a tick
+   |
+LL |     'label: loop { continue 'label };
+   |                             +
 
 error[E0425]: cannot find value `label` in this scope
   --> $DIR/recover-unticked-labels.rs:4:26
diff --git a/tests/ui/parser/regions-out-of-scope-slice.stderr b/tests/ui/parser/regions-out-of-scope-slice.stderr
index 5d8f6af166b..838dcde2850 100644
--- a/tests/ui/parser/regions-out-of-scope-slice.stderr
+++ b/tests/ui/parser/regions-out-of-scope-slice.stderr
@@ -2,10 +2,15 @@ error: borrow expressions cannot be annotated with lifetimes
   --> $DIR/regions-out-of-scope-slice.rs:7:13
    |
 LL |         x = &'blk [1,2,3];
-   |             ^----^^^^^^^^
+   |             ^-----^^^^^^^
    |              |
    |              annotated with lifetime here
-   |              help: remove the lifetime annotation
+   |
+help: remove the lifetime annotation
+   |
+LL -         x = &'blk [1,2,3];
+LL +         x = &[1,2,3];
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr
index c089e0ba969..0cdee1d51ea 100644
--- a/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr
+++ b/tests/ui/parser/removed-syntax/removed-syntax-fn-sigil.stderr
@@ -2,7 +2,12 @@ error: missing parameters for function definition
   --> $DIR/removed-syntax-fn-sigil.rs:2:14
    |
 LL |     let x: fn~() = || ();
-   |              ^ help: add a parameter list
+   |              ^
+   |
+help: add a parameter list
+   |
+LL |     let x: fn()~() = || ();
+   |              ++
 
 error: expected one of `->`, `;`, or `=`, found `~`
   --> $DIR/removed-syntax-fn-sigil.rs:2:14
diff --git a/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr b/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr
index 52e0658949d..d3ed7fc6376 100644
--- a/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr
+++ b/tests/ui/parser/removed-syntax/removed-syntax-static-fn.stderr
@@ -19,7 +19,12 @@ error: missing type for `static` item
   --> $DIR/removed-syntax-static-fn.rs:4:14
    |
 LL |     static fn f() {}
-   |              ^ help: provide a type for the item: `: <type>`
+   |              ^
+   |
+help: provide a type for the item
+   |
+LL |     static fn: <type> f() {}
+   |              ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
index 7f16ebcfc3a..1fb57ab11f9 100644
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
+++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
@@ -2,37 +2,73 @@ error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:9:16
    |
 LL |     field1: i32 = 42,
-   |                ^^^^^ help: remove this unsupported default value
+   |                ^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field1: i32 = 42,
+LL +     field1: i32,
+   |
 
 error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:10:14
    |
 LL |     field2: E = E::A,
-   |              ^^^^^^^ help: remove this unsupported default value
+   |              ^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field2: E = E::A,
+LL +     field2: E,
+   |
 
 error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16
    |
 LL |     field3: i32 = 1 + 2,
-   |                ^^^^^^^^ help: remove this unsupported default value
+   |                ^^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field3: i32 = 1 + 2,
+LL +     field3: i32,
+   |
 
 error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:12:16
    |
 LL |     field4: i32 = { 1 + 2 },
-   |                ^^^^^^^^^^^^ help: remove this unsupported default value
+   |                ^^^^^^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field4: i32 = { 1 + 2 },
+LL +     field4: i32,
+   |
 
 error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14
    |
 LL |     field5: E = foo(42),
-   |              ^^^^^^^^^^ help: remove this unsupported default value
+   |              ^^^^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field5: E = foo(42),
+LL +     field5: E,
+   |
 
 error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:14:14
    |
 LL |     field6: E = { foo(42) },
-   |              ^^^^^^^^^^^^^^ help: remove this unsupported default value
+   |              ^^^^^^^^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field6: E = { foo(42) },
+LL +     field6: E,
+   |
 
 error: expected `,`, or `}`, found `field2`
   --> $DIR/struct-default-values-and-missing-field-separator.rs:18:16
@@ -50,25 +86,49 @@ error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16
    |
 LL |     field3: i32 = 1 + 2,
-   |                ^^^^^^^^ help: remove this unsupported default value
+   |                ^^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field3: i32 = 1 + 2,
+LL +     field3: i32,
+   |
 
 error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:21:16
    |
 LL |     field4: i32 = { 1 + 2 },
-   |                ^^^^^^^^^^^^ help: remove this unsupported default value
+   |                ^^^^^^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field4: i32 = { 1 + 2 },
+LL +     field4: i32,
+   |
 
 error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14
    |
 LL |     field5: E = foo(42),
-   |              ^^^^^^^^^^ help: remove this unsupported default value
+   |              ^^^^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field5: E = foo(42),
+LL +     field5: E,
+   |
 
 error: default values on `struct` fields aren't supported
   --> $DIR/struct-default-values-and-missing-field-separator.rs:23:14
    |
 LL |     field6: E = { foo(42) },
-   |              ^^^^^^^^^^^^^^ help: remove this unsupported default value
+   |              ^^^^^^^^^^^^^^
+   |
+help: remove this unsupported default value
+   |
+LL -     field6: E = { foo(42) },
+LL +     field6: E,
+   |
 
 error: expected `:`, found `=`
   --> $DIR/struct-default-values-and-missing-field-separator.rs:27:12
diff --git a/tests/ui/parser/suggest-assoc-const.stderr b/tests/ui/parser/suggest-assoc-const.stderr
index 6e29fad98d4..70ebeded313 100644
--- a/tests/ui/parser/suggest-assoc-const.stderr
+++ b/tests/ui/parser/suggest-assoc-const.stderr
@@ -2,7 +2,12 @@ error: non-item in item list
   --> $DIR/suggest-assoc-const.rs:5:5
    |
 LL |     let _X: i32;
-   |     ^^^ help: consider using `const` instead of `let` for associated const: `const`
+   |     ^^^
+   |
+help: consider using `const` instead of `let` for associated const
+   |
+LL |     const _X: i32;
+   |     ~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr
index 5f175e86545..be130ac7ab2 100644
--- a/tests/ui/parser/trait-object-delimiters.stderr
+++ b/tests/ui/parser/trait-object-delimiters.stderr
@@ -2,7 +2,12 @@ error: ambiguous `+` in a type
   --> $DIR/trait-object-delimiters.rs:3:13
    |
 LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
-   |             ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef<str>)`
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL | fn foo1(_: &(dyn Drop + AsRef<str>)) {}
+   |             +                     +
 
 error: incorrect parentheses around trait bounds
   --> $DIR/trait-object-delimiters.rs:6:17
@@ -52,9 +57,14 @@ error: invalid `dyn` keyword
   --> $DIR/trait-object-delimiters.rs:16:25
    |
 LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
-   |                         ^^^ help: remove this keyword
+   |                         ^^^
    |
    = help: `dyn` is only needed at the start of a trait `+`-separated list
+help: remove this keyword
+   |
+LL - fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
+LL + fn foo5(_: &(dyn Drop + AsRef<str>)) {}
+   |
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/trait-object-delimiters.rs:3:24
diff --git a/tests/ui/parser/trait-object-lifetime-parens.stderr b/tests/ui/parser/trait-object-lifetime-parens.stderr
index 9c7a9662c40..280c0e40c64 100644
--- a/tests/ui/parser/trait-object-lifetime-parens.stderr
+++ b/tests/ui/parser/trait-object-lifetime-parens.stderr
@@ -2,13 +2,25 @@ error: parenthesized lifetime bounds are not supported
   --> $DIR/trait-object-lifetime-parens.rs:5:21
    |
 LL | fn f<'a, T: Trait + ('a)>() {}
-   |                     ^^^^ help: remove the parentheses
+   |                     ^^^^
+   |
+help: remove the parentheses
+   |
+LL - fn f<'a, T: Trait + ('a)>() {}
+LL + fn f<'a, T: Trait + 'a>() {}
+   |
 
 error: parenthesized lifetime bounds are not supported
   --> $DIR/trait-object-lifetime-parens.rs:8:24
    |
 LL |     let _: Box<Trait + ('a)>;
-   |                        ^^^^ help: remove the parentheses
+   |                        ^^^^
+   |
+help: remove the parentheses
+   |
+LL -     let _: Box<Trait + ('a)>;
+LL +     let _: Box<Trait + 'a>;
+   |
 
 error: lifetime in trait object type must be followed by `+`
   --> $DIR/trait-object-lifetime-parens.rs:10:17
diff --git a/tests/ui/parser/trait-object-polytrait-priority.rs b/tests/ui/parser/trait-object-polytrait-priority.rs
index 63425f3e201..e7f085104ae 100644
--- a/tests/ui/parser/trait-object-polytrait-priority.rs
+++ b/tests/ui/parser/trait-object-polytrait-priority.rs
@@ -6,5 +6,4 @@ fn main() {
     let _: &for<'a> Trait<'a> + 'static;
     //~^ ERROR expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>`
     //~| HELP try adding parentheses
-    //~| SUGGESTION &(for<'a> Trait<'a> + 'static)
 }
diff --git a/tests/ui/parser/trait-object-polytrait-priority.stderr b/tests/ui/parser/trait-object-polytrait-priority.stderr
index 23ec1e9cf3d..8cb564e7930 100644
--- a/tests/ui/parser/trait-object-polytrait-priority.stderr
+++ b/tests/ui/parser/trait-object-polytrait-priority.stderr
@@ -2,7 +2,12 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait<
   --> $DIR/trait-object-polytrait-priority.rs:6:12
    |
 LL |     let _: &for<'a> Trait<'a> + 'static;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&(for<'a> Trait<'a> + 'static)`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try adding parentheses
+   |
+LL |     let _: &(for<'a> Trait<'a> + 'static);
+   |             +                           +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr
index 726cde2b413..a1561e7f04b 100644
--- a/tests/ui/parser/unicode-character-literal.stderr
+++ b/tests/ui/parser/unicode-character-literal.stderr
@@ -34,15 +34,17 @@ error: character literal may only contain one codepoint
   --> $DIR/unicode-character-literal.rs:17:14
    |
 LL |     let _a = 'AĚŠ';
-   |              ^-^
-   |               |
-   |               help: consider using the normalized form `\u{c5}` of this character: `Ă…`
+   |              ^^^
    |
 note: this `A` is followed by the combining mark `\u{30a}`
   --> $DIR/unicode-character-literal.rs:17:15
    |
 LL |     let _a = 'AĚŠ';
    |               ^
+help: consider using the normalized form `\u{c5}` of this character
+   |
+LL |     let _a = 'Ă…';
+   |               ~
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/unmatched-langle-1.stderr b/tests/ui/parser/unmatched-langle-1.stderr
index cdf74bdedc2..3411a05fb58 100644
--- a/tests/ui/parser/unmatched-langle-1.stderr
+++ b/tests/ui/parser/unmatched-langle-1.stderr
@@ -2,7 +2,13 @@ error: unmatched angle brackets
   --> $DIR/unmatched-langle-1.rs:5:10
    |
 LL |     foo::<<<<Ty<i32>>();
-   |          ^^^ help: remove extra angle brackets
+   |          ^^^
+   |
+help: remove extra angle brackets
+   |
+LL -     foo::<<<<Ty<i32>>();
+LL +     foo::<Ty<i32>>();
+   |
 
 error[E0412]: cannot find type `Ty` in this scope
   --> $DIR/unmatched-langle-1.rs:5:14
diff --git a/tests/ui/parser/unnecessary-let.stderr b/tests/ui/parser/unnecessary-let.stderr
index 952119cae3e..c6ac0d562f8 100644
--- a/tests/ui/parser/unnecessary-let.stderr
+++ b/tests/ui/parser/unnecessary-let.stderr
@@ -2,19 +2,36 @@ error: expected pattern, found `let`
   --> $DIR/unnecessary-let.rs:2:9
    |
 LL |     for let x of [1, 2, 3] {}
-   |         ^^^ help: remove the unnecessary `let` keyword
+   |         ^^^
+   |
+help: remove the unnecessary `let` keyword
+   |
+LL -     for let x of [1, 2, 3] {}
+LL +     for  x of [1, 2, 3] {}
+   |
 
 error: missing `in` in `for` loop
   --> $DIR/unnecessary-let.rs:2:15
    |
 LL |     for let x of [1, 2, 3] {}
-   |               ^^ help: try using `in` here instead
+   |               ^^
+   |
+help: try using `in` here instead
+   |
+LL |     for let x in [1, 2, 3] {}
+   |               ~~
 
 error: expected pattern, found `let`
   --> $DIR/unnecessary-let.rs:7:9
    |
 LL |         let 1 => {}
-   |         ^^^ help: remove the unnecessary `let` keyword
+   |         ^^^
+   |
+help: remove the unnecessary `let` keyword
+   |
+LL -         let 1 => {}
+LL +          1 => {}
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/use-colon-as-mod-sep.stderr b/tests/ui/parser/use-colon-as-mod-sep.stderr
index bfc5374ef9d..347b271df99 100644
--- a/tests/ui/parser/use-colon-as-mod-sep.stderr
+++ b/tests/ui/parser/use-colon-as-mod-sep.stderr
@@ -2,33 +2,49 @@ error: expected `::`, found `:`
   --> $DIR/use-colon-as-mod-sep.rs:3:17
    |
 LL | use std::process:Command;
-   |                 ^ help: use double colon
+   |                 ^
    |
    = note: import paths are delimited using `::`
+help: use double colon
+   |
+LL | use std::process::Command;
+   |                 ~~
 
 error: expected `::`, found `:`
   --> $DIR/use-colon-as-mod-sep.rs:5:8
    |
 LL | use std:fs::File;
-   |        ^ help: use double colon
+   |        ^
    |
    = note: import paths are delimited using `::`
+help: use double colon
+   |
+LL | use std::fs::File;
+   |        ~~
 
 error: expected `::`, found `:`
   --> $DIR/use-colon-as-mod-sep.rs:7:8
    |
 LL | use std:collections:HashMap;
-   |        ^ help: use double colon
+   |        ^
    |
    = note: import paths are delimited using `::`
+help: use double colon
+   |
+LL | use std::collections:HashMap;
+   |        ~~
 
 error: expected `::`, found `:`
   --> $DIR/use-colon-as-mod-sep.rs:7:20
    |
 LL | use std:collections:HashMap;
-   |                    ^ help: use double colon
+   |                    ^
    |
    = note: import paths are delimited using `::`
+help: use double colon
+   |
+LL | use std:collections::HashMap;
+   |                    ~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr
index 2f45415844d..1599edd7a99 100644
--- a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr
+++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr
@@ -6,7 +6,11 @@ LL |     let _ @ a = 0;
    |         |   |
    |         |   binding on the right, should be on the left
    |         pattern on the left, should be on the right
-   |         help: switch the order: `a @ _`
+   |
+help: switch the order
+   |
+LL |     let a @ _ = 0;
+   |         ~~~~~
 
 error: pattern on wrong side of `@`
   --> $DIR/wild-before-at-syntactically-rejected.rs:10:9
@@ -16,7 +20,11 @@ LL |     let _ @ ref a = 0;
    |         |   |
    |         |   binding on the right, should be on the left
    |         pattern on the left, should be on the right
-   |         help: switch the order: `ref a @ _`
+   |
+help: switch the order
+   |
+LL |     let ref a @ _ = 0;
+   |         ~~~~~~~~~
 
 error: pattern on wrong side of `@`
   --> $DIR/wild-before-at-syntactically-rejected.rs:12:9
@@ -26,7 +34,11 @@ LL |     let _ @ ref mut a = 0;
    |         |   |
    |         |   binding on the right, should be on the left
    |         pattern on the left, should be on the right
-   |         help: switch the order: `ref mut a @ _`
+   |
+help: switch the order
+   |
+LL |     let ref mut a @ _ = 0;
+   |         ~~~~~~~~~~~~~
 
 error: left-hand side of `@` must be a binding
   --> $DIR/wild-before-at-syntactically-rejected.rs:14:9
diff --git a/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr
index 167016397d2..622358126b0 100644
--- a/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr
+++ b/tests/ui/pattern/issue-80186-mut-binding-help-suggestion.stderr
@@ -2,9 +2,13 @@ error: `mut` must be attached to each individual binding
   --> $DIR/issue-80186-mut-binding-help-suggestion.rs:5:9
    |
 LL |     let mut &x = &0;
-   |         ^^^^^^ help: add `mut` to each binding: `&(mut x)`
+   |         ^^^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: add `mut` to each binding
+   |
+LL |     let &(mut x) = &0;
+   |         ~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/pattern-bad-ref-box-order.stderr b/tests/ui/pattern/pattern-bad-ref-box-order.stderr
index a49f05c1028..a89d3ed21b6 100644
--- a/tests/ui/pattern/pattern-bad-ref-box-order.stderr
+++ b/tests/ui/pattern/pattern-bad-ref-box-order.stderr
@@ -2,7 +2,12 @@ error: switch the order of `ref` and `box`
   --> $DIR/pattern-bad-ref-box-order.rs:8:14
    |
 LL |         Some(ref box _i) => {},
-   |              ^^^^^^^ help: swap them: `box ref`
+   |              ^^^^^^^
+   |
+help: swap them
+   |
+LL |         Some(box ref _i) => {},
+   |              ~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
index 37c02eb6ada..9d642b9245a 100644
--- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
+++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
@@ -2,7 +2,12 @@ error: range-to patterns with `...` are not allowed
   --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:17:13
    |
 LL |         [_, ...tail] => println!("{tail}"),
-   |             ^^^ help: use `..=` instead
+   |             ^^^
+   |
+help: use `..=` instead
+   |
+LL |         [_, ..=tail] => println!("{tail}"),
+   |             ~~~
 
 error[E0425]: cannot find value `rest` in this scope
   --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13
diff --git a/tests/ui/pub/pub-restricted.stderr b/tests/ui/pub/pub-restricted.stderr
index 4694530e548..fc177aa2033 100644
--- a/tests/ui/pub/pub-restricted.stderr
+++ b/tests/ui/pub/pub-restricted.stderr
@@ -2,56 +2,76 @@ error[E0704]: incorrect visibility restriction
   --> $DIR/pub-restricted.rs:3:6
    |
 LL | pub (a) fn afn() {}
-   |      ^ help: make this visible only to module `a` with `in`: `in a`
+   |      ^
    |
    = help: some possible visibility restrictions are:
            `pub(crate)`: visible only on the current crate
            `pub(super)`: visible only in the current module's parent
            `pub(in path::to::module)`: visible only on the specified path
+help: make this visible only to module `a` with `in`
+   |
+LL | pub (in a) fn afn() {}
+   |      ~~~~
 
 error[E0704]: incorrect visibility restriction
   --> $DIR/pub-restricted.rs:4:6
    |
 LL | pub (b) fn bfn() {}
-   |      ^ help: make this visible only to module `b` with `in`: `in b`
+   |      ^
    |
    = help: some possible visibility restrictions are:
            `pub(crate)`: visible only on the current crate
            `pub(super)`: visible only in the current module's parent
            `pub(in path::to::module)`: visible only on the specified path
+help: make this visible only to module `b` with `in`
+   |
+LL | pub (in b) fn bfn() {}
+   |      ~~~~
 
 error[E0704]: incorrect visibility restriction
   --> $DIR/pub-restricted.rs:5:6
    |
 LL | pub (crate::a) fn cfn() {}
-   |      ^^^^^^^^ help: make this visible only to module `crate::a` with `in`: `in crate::a`
+   |      ^^^^^^^^
    |
    = help: some possible visibility restrictions are:
            `pub(crate)`: visible only on the current crate
            `pub(super)`: visible only in the current module's parent
            `pub(in path::to::module)`: visible only on the specified path
+help: make this visible only to module `crate::a` with `in`
+   |
+LL | pub (in crate::a) fn cfn() {}
+   |      ~~~~~~~~~~~
 
 error[E0704]: incorrect visibility restriction
   --> $DIR/pub-restricted.rs:22:14
    |
 LL |         pub (a) invalid: usize,
-   |              ^ help: make this visible only to module `a` with `in`: `in a`
+   |              ^
    |
    = help: some possible visibility restrictions are:
            `pub(crate)`: visible only on the current crate
            `pub(super)`: visible only in the current module's parent
            `pub(in path::to::module)`: visible only on the specified path
+help: make this visible only to module `a` with `in`
+   |
+LL |         pub (in a) invalid: usize,
+   |              ~~~~
 
 error[E0704]: incorrect visibility restriction
   --> $DIR/pub-restricted.rs:31:6
    |
 LL | pub (xyz) fn xyz() {}
-   |      ^^^ help: make this visible only to module `xyz` with `in`: `in xyz`
+   |      ^^^
    |
    = help: some possible visibility restrictions are:
            `pub(crate)`: visible only on the current crate
            `pub(super)`: visible only in the current module's parent
            `pub(in path::to::module)`: visible only on the specified path
+help: make this visible only to module `xyz` with `in`
+   |
+LL | pub (in xyz) fn xyz() {}
+   |      ~~~~~~
 
 error[E0742]: visibilities can only be restricted to ancestor modules
   --> $DIR/pub-restricted.rs:23:17
diff --git a/tests/ui/range/impossible_range.stderr b/tests/ui/range/impossible_range.stderr
index 53c56065c2a..17dd264e366 100644
--- a/tests/ui/range/impossible_range.stderr
+++ b/tests/ui/range/impossible_range.stderr
@@ -2,17 +2,27 @@ error[E0586]: inclusive range with no end
   --> $DIR/impossible_range.rs:11:5
    |
 LL |     ..=;
-   |     ^^^ help: use `..` instead
+   |     ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     ..=;
+LL +     ..;
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/impossible_range.rs:18:6
    |
 LL |     0..=;
-   |      ^^^ help: use `..` instead
+   |      ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL -     0..=;
+LL +     0..;
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/range/range-inclusive-pattern-precedence.stderr b/tests/ui/range/range-inclusive-pattern-precedence.stderr
index 2e2d7983c03..9df20fc4545 100644
--- a/tests/ui/range/range-inclusive-pattern-precedence.stderr
+++ b/tests/ui/range/range-inclusive-pattern-precedence.stderr
@@ -2,7 +2,12 @@ error: the range pattern here has ambiguous interpretation
   --> $DIR/range-inclusive-pattern-precedence.rs:15:10
    |
 LL |         &10..=15 => {}
-   |          ^^^^^^^ help: add parentheses to clarify the precedence: `(10..=15)`
+   |          ^^^^^^^
+   |
+help: add parentheses to clarify the precedence
+   |
+LL |         &(10..=15) => {}
+   |          +       +
 
 warning: `...` range patterns are deprecated
   --> $DIR/range-inclusive-pattern-precedence.rs:11:9
diff --git a/tests/ui/range/range-inclusive-pattern-precedence2.stderr b/tests/ui/range/range-inclusive-pattern-precedence2.stderr
index 84294604c80..fd2fa78e92b 100644
--- a/tests/ui/range/range-inclusive-pattern-precedence2.stderr
+++ b/tests/ui/range/range-inclusive-pattern-precedence2.stderr
@@ -2,7 +2,12 @@ error: the range pattern here has ambiguous interpretation
   --> $DIR/range-inclusive-pattern-precedence2.rs:14:13
    |
 LL |         box 10..=15 => {}
-   |             ^^^^^^^ help: add parentheses to clarify the precedence: `(10..=15)`
+   |             ^^^^^^^
+   |
+help: add parentheses to clarify the precedence
+   |
+LL |         box (10..=15) => {}
+   |             +       +
 
 warning: `...` range patterns are deprecated
   --> $DIR/range-inclusive-pattern-precedence2.rs:10:14
diff --git a/tests/ui/recursion/issue-83150.rs b/tests/ui/recursion/issue-83150.rs
index b3ddf88c449..f91698d0637 100644
--- a/tests/ui/recursion/issue-83150.rs
+++ b/tests/ui/recursion/issue-83150.rs
@@ -1,3 +1,4 @@
+//~ ERROR overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>: Iterator`
 //@ build-fail
 //@ compile-flags: -Copt-level=0
 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
@@ -11,5 +12,4 @@ fn main() {
 fn func<T: Iterator<Item = u8>>(iter: &mut T) {
     //~^ WARN function cannot return without recursing
     func(&mut iter.map(|x| x + 1))
-    //~^ ERROR reached the type-length limit
 }
diff --git a/tests/ui/recursion/issue-83150.stderr b/tests/ui/recursion/issue-83150.stderr
index 127de98ddc5..fb66436dbbd 100644
--- a/tests/ui/recursion/issue-83150.stderr
+++ b/tests/ui/recursion/issue-83150.stderr
@@ -1,5 +1,5 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-83150.rs:11:1
+  --> $DIR/issue-83150.rs:12:1
    |
 LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -10,14 +10,13 @@ LL |     func(&mut iter.map(|x| x + 1))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error: reached the type-length limit while instantiating `<&mut Map<&mut Map<&mut ..., ...>, ...> as Iterator>::map::<..., ...>`
-  --> $DIR/issue-83150.rs:13:15
+error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>: Iterator`
    |
-LL |     func(&mut iter.map(|x| x + 1))
-   |               ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding a `#![type_length_limit="23068663"]` attribute to your crate
-   = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type.txt'
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
+   = note: required for `&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>` to implement `Iterator`
+   = note: 65 redundant requirements hidden
+   = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>, {closure@$DIR/issue-83150.rs:14:24: 14:27}>` to implement `Iterator`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr
index 8a1ed8f3b9c..350ac287507 100644
--- a/tests/ui/repeat-expr/repeat_count.stderr
+++ b/tests/ui/repeat-expr/repeat_count.stderr
@@ -1,10 +1,13 @@
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/repeat_count.rs:5:17
    |
-LL |     let n = 1;
-   |     ----- help: consider using `const` instead of `let`: `const n`
 LL |     let a = [0; n];
    |                 ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const n: /* Type */ = 1;
+   |     ~~~~~  ++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/repeat_count.rs:7:17
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr
index 17d1b7e0d43..05980510f1c 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/parse.stderr
@@ -2,13 +2,23 @@ error: expected `,` following `match` arm
   --> $DIR/parse.rs:26:16
    |
 LL |         Some(!)
-   |                ^ help: missing a comma here to end this `match` arm: `,`
+   |                ^
+   |
+help: missing a comma here to end this `match` arm
+   |
+LL |         Some(!),
+   |                +
 
 error: expected `,` following `match` arm
   --> $DIR/parse.rs:31:24
    |
 LL |         Some(!) if true
-   |                        ^ help: missing a comma here to end this `match` arm: `,`
+   |                        ^
+   |
+help: missing a comma here to end this `match` arm
+   |
+LL |         Some(!) if true,
+   |                        +
 
 error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `<=`
   --> $DIR/parse.rs:42:17
@@ -20,7 +30,12 @@ error: top-level or-patterns are not allowed in `let` bindings
   --> $DIR/parse.rs:67:9
    |
 LL |     let Ok(_) | Err(!) = &res; // Disallowed; see #82048.
-   |         ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Ok(_) | Err(!))`
+   |         ^^^^^^^^^^^^^^
+   |
+help: wrap the pattern in parentheses
+   |
+LL |     let (Ok(_) | Err(!)) = &res; // Disallowed; see #82048.
+   |         +              +
 
 error: never patterns cannot contain variable bindings
   --> $DIR/parse.rs:73:9
diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
index c2b9899e20d..f515cb62c7c 100644
--- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
+++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
@@ -9,6 +9,10 @@ LL |     let _ = dbg!(a);
    |             ^^^^^^^ value used here after move
    |
    = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing instead of transferring ownership
+   |
+LL |     let _ = dbg!(&a);
+   |                  +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs
new file mode 100644
index 00000000000..21e91c731b3
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs
@@ -0,0 +1,24 @@
+#![feature(generic_const_exprs)]
+//~^ WARN: the feature `generic_const_exprs` is incomplete
+
+// Regression test for #125770 which would ICE under the old effects desugaring that
+// created a const generic parameter for constness on `Add`.
+
+use std::ops::Add;
+
+pub struct Dimension;
+
+pub struct Quantity<S, const D: Dimension>(S);
+//~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter
+
+impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
+//~^ ERROR: trait takes at most 1 generic argument
+//~| ERROR: `Dimension` is forbidden as the type of a const generic parameter
+
+pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
+    //~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter
+    x + y
+    //~^ ERROR: cannot find value `y` in this scope
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
new file mode 100644
index 00000000000..8c814295de4
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
@@ -0,0 +1,64 @@
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/mismatched_generic_args.rs:20:9
+   |
+LL | pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
+   |                  - similarly named const parameter `U` defined here
+LL |
+LL |     x + y
+   |         ^ help: a const parameter with a similar name exists: `U`
+
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/mismatched_generic_args.rs:1:12
+   |
+LL | #![feature(generic_const_exprs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: `Dimension` is forbidden as the type of a const generic parameter
+  --> $DIR/mismatched_generic_args.rs:11:33
+   |
+LL | pub struct Quantity<S, const D: Dimension>(S);
+   |                                 ^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
+   |
+LL + #![feature(adt_const_params)]
+   |
+
+error[E0107]: trait takes at most 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/mismatched_generic_args.rs:14:36
+   |
+LL | impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
+   |                                    ^^^ expected at most 1 generic argument
+
+error: `Dimension` is forbidden as the type of a const generic parameter
+  --> $DIR/mismatched_generic_args.rs:14:15
+   |
+LL | impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
+   |               ^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
+   |
+LL + #![feature(adt_const_params)]
+   |
+
+error: `Dimension` is forbidden as the type of a const generic parameter
+  --> $DIR/mismatched_generic_args.rs:18:21
+   |
+LL | pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
+   |                     ^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
+   |
+LL + #![feature(adt_const_params)]
+   |
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0107, E0425.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/self/self-vs-path-ambiguity.stderr b/tests/ui/self/self-vs-path-ambiguity.stderr
index 9e140e21023..557a63a2af1 100644
--- a/tests/ui/self/self-vs-path-ambiguity.stderr
+++ b/tests/ui/self/self-vs-path-ambiguity.stderr
@@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/self-vs-path-ambiguity.rs:9:11
    |
 LL |     fn i(&'a self::S: &S) {}
-   |           ^^ help: remove the lifetime
+   |           ^^
+   |
+help: remove the lifetime
+   |
+LL -     fn i(&'a self::S: &S) {}
+LL +     fn i(&self::S: &S) {}
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr
index 4909a9cdc7f..8298293a8cb 100644
--- a/tests/ui/self/self_type_keyword.stderr
+++ b/tests/ui/self/self_type_keyword.stderr
@@ -14,9 +14,14 @@ error: `mut` must be followed by a named binding
   --> $DIR/self_type_keyword.rs:16:9
    |
 LL |         mut Self => (),
-   |         ^^^^ help: remove the `mut` prefix
+   |         ^^^^
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
+help: remove the `mut` prefix
+   |
+LL -         mut Self => (),
+LL +         Self => (),
+   |
 
 error: expected identifier, found keyword `Self`
   --> $DIR/self_type_keyword.rs:19:17
diff --git a/tests/ui/structs/struct-duplicate-comma.stderr b/tests/ui/structs/struct-duplicate-comma.stderr
index 4ac3fc9fe6b..dc1c6ae8716 100644
--- a/tests/ui/structs/struct-duplicate-comma.stderr
+++ b/tests/ui/structs/struct-duplicate-comma.stderr
@@ -4,10 +4,13 @@ error: expected identifier, found `,`
 LL |     let _ = Foo {
    |             --- while parsing this struct
 LL |         a: 0,,
-   |              ^
-   |              |
-   |              expected identifier
-   |              help: remove this comma
+   |              ^ expected identifier
+   |
+help: remove this comma
+   |
+LL -         a: 0,,
+LL +         a: 0,
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/structs/struct-field-init-syntax.stderr b/tests/ui/structs/struct-field-init-syntax.stderr
index 0b72c5cf734..66098d5f610 100644
--- a/tests/ui/structs/struct-field-init-syntax.stderr
+++ b/tests/ui/structs/struct-field-init-syntax.stderr
@@ -2,17 +2,27 @@ error: cannot use a comma after the base struct
   --> $DIR/struct-field-init-syntax.rs:11:9
    |
 LL |         ..Foo::default(),
-   |         ^^^^^^^^^^^^^^^^- help: remove this comma
+   |         ^^^^^^^^^^^^^^^^
    |
    = note: the base struct must always be the last field
+help: remove this comma
+   |
+LL -         ..Foo::default(),
+LL +         ..Foo::default()
+   |
 
 error: cannot use a comma after the base struct
   --> $DIR/struct-field-init-syntax.rs:16:9
    |
 LL |         ..Foo::default(),
-   |         ^^^^^^^^^^^^^^^^- help: remove this comma
+   |         ^^^^^^^^^^^^^^^^
    |
    = note: the base struct must always be the last field
+help: remove this comma
+   |
+LL -         ..Foo::default(),
+LL +         ..Foo::default()
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/const-no-type.stderr b/tests/ui/suggestions/const-no-type.stderr
index bd703992fd4..c85c5898907 100644
--- a/tests/ui/suggestions/const-no-type.stderr
+++ b/tests/ui/suggestions/const-no-type.stderr
@@ -26,19 +26,34 @@ error: missing type for `const` item
   --> $DIR/const-no-type.rs:14:9
    |
 LL | const C2 = 42;
-   |         ^ help: provide a type for the item: `: <type>`
+   |         ^
+   |
+help: provide a type for the item
+   |
+LL | const C2: <type> = 42;
+   |         ++++++++
 
 error: missing type for `static` item
   --> $DIR/const-no-type.rs:20:10
    |
 LL | static S2 = "abc";
-   |          ^ help: provide a type for the item: `: <type>`
+   |          ^
+   |
+help: provide a type for the item
+   |
+LL | static S2: <type> = "abc";
+   |          ++++++++
 
 error: missing type for `static mut` item
   --> $DIR/const-no-type.rs:26:15
    |
 LL | static mut SM2 = "abc";
-   |               ^ help: provide a type for the item: `: <type>`
+   |               ^
+   |
+help: provide a type for the item
+   |
+LL | static mut SM2: <type> = "abc";
+   |               ++++++++
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/suggestions/js-style-comparison-op.stderr b/tests/ui/suggestions/js-style-comparison-op.stderr
index 33f7a0844fd..58b1fddd3dd 100644
--- a/tests/ui/suggestions/js-style-comparison-op.stderr
+++ b/tests/ui/suggestions/js-style-comparison-op.stderr
@@ -2,13 +2,23 @@ error: invalid comparison operator `===`
   --> $DIR/js-style-comparison-op.rs:3:10
    |
 LL |     if 1 === 1 {
-   |          ^^^ help: `===` is not a valid comparison operator, use `==`
+   |          ^^^
+   |
+help: `===` is not a valid comparison operator, use `==`
+   |
+LL |     if 1 == 1 {
+   |          ~~
 
 error: invalid comparison operator `!==`
   --> $DIR/js-style-comparison-op.rs:5:17
    |
 LL |     } else if 1 !== 1 {
-   |                 ^^^ help: `!==` is not a valid comparison operator, use `!=`
+   |                 ^^^
+   |
+help: `!==` is not a valid comparison operator, use `!=`
+   |
+LL |     } else if 1 != 1 {
+   |                 ~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr b/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr
index e068fdb5aba..dd8f896d88e 100644
--- a/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr
+++ b/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr
@@ -2,25 +2,40 @@ error: expected item, found `;`
   --> $DIR/recover-from-semicolon-trailing-item.rs:2:9
    |
 LL | mod M {};
-   |         ^ help: remove this semicolon
+   |         ^
    |
    = help: module declarations are not followed by a semicolon
+help: remove this semicolon
+   |
+LL - mod M {};
+LL + mod M {}
+   |
 
 error: expected item, found `;`
   --> $DIR/recover-from-semicolon-trailing-item.rs:4:12
    |
 LL | struct S {};
-   |            ^ help: remove this semicolon
+   |            ^
    |
    = help: braced struct declarations are not followed by a semicolon
+help: remove this semicolon
+   |
+LL - struct S {};
+LL + struct S {}
+   |
 
 error: expected item, found `;`
   --> $DIR/recover-from-semicolon-trailing-item.rs:6:20
    |
 LL | fn foo(a: usize) {};
-   |                    ^ help: remove this semicolon
+   |                    ^
    |
    = help: function declarations are not followed by a semicolon
+help: remove this semicolon
+   |
+LL - fn foo(a: usize) {};
+LL + fn foo(a: usize) {}
+   |
 
 error[E0308]: mismatched types
   --> $DIR/recover-from-semicolon-trailing-item.rs:10:20
diff --git a/tests/ui/suggestions/recover-invalid-float.stderr b/tests/ui/suggestions/recover-invalid-float.stderr
index dd24746eab8..9e4ea6d3089 100644
--- a/tests/ui/suggestions/recover-invalid-float.stderr
+++ b/tests/ui/suggestions/recover-invalid-float.stderr
@@ -2,19 +2,34 @@ error: float literals must have an integer part
   --> $DIR/recover-invalid-float.rs:4:18
    |
 LL |     let _: f32 = .3;
-   |                  ^^ help: must have an integer part: `0.3`
+   |                  ^^
+   |
+help: must have an integer part
+   |
+LL |     let _: f32 = 0.3;
+   |                  +
 
 error: float literals must have an integer part
   --> $DIR/recover-invalid-float.rs:6:18
    |
 LL |     let _: f32 = .42f32;
-   |                  ^^^^^^ help: must have an integer part: `0.42f32`
+   |                  ^^^^^^
+   |
+help: must have an integer part
+   |
+LL |     let _: f32 = 0.42f32;
+   |                  +
 
 error: float literals must have an integer part
   --> $DIR/recover-invalid-float.rs:8:18
    |
 LL |     let _: f64 = .5f64;
-   |                  ^^^^^ help: must have an integer part: `0.5f64`
+   |                  ^^^^^
+   |
+help: must have an integer part
+   |
+LL |     let _: f64 = 0.5f64;
+   |                  +
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/suggestions/type-ascription-instead-of-method.stderr b/tests/ui/suggestions/type-ascription-instead-of-method.stderr
index 3242b028d5d..0bef1c185db 100644
--- a/tests/ui/suggestions/type-ascription-instead-of-method.stderr
+++ b/tests/ui/suggestions/type-ascription-instead-of-method.stderr
@@ -2,9 +2,13 @@ error: path separator must be a double colon
   --> $DIR/type-ascription-instead-of-method.rs:3:16
    |
 LL |     let _ = Box:new("foo".to_string());
-   |                ^ help: use a double colon instead: `::`
+   |                ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a double colon instead
+   |
+LL |     let _ = Box::new("foo".to_string());
+   |                 +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/type-ascription-instead-of-path.stderr b/tests/ui/suggestions/type-ascription-instead-of-path.stderr
index 566b036e53e..8c16acff799 100644
--- a/tests/ui/suggestions/type-ascription-instead-of-path.stderr
+++ b/tests/ui/suggestions/type-ascription-instead-of-path.stderr
@@ -2,9 +2,13 @@ error: path separator must be a double colon
   --> $DIR/type-ascription-instead-of-path.rs:2:8
    |
 LL |     std:io::stdin();
-   |        ^ help: use a double colon instead: `::`
+   |        ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a double colon instead
+   |
+LL |     std::io::stdin();
+   |         +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr
index 6fea7f94052..f0b31722e40 100644
--- a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr
+++ b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr
@@ -2,9 +2,13 @@ error: path separator must be a double colon
   --> $DIR/type-ascription-instead-of-variant.rs:3:19
    |
 LL |     let _ = Option:Some("");
-   |                   ^ help: use a double colon instead: `::`
+   |                   ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a double colon instead
+   |
+LL |     let _ = Option::Some("");
+   |                    +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/tool-attributes/invalid-tool.rs b/tests/ui/tool-attributes/invalid-tool.rs
new file mode 100644
index 00000000000..125333231d2
--- /dev/null
+++ b/tests/ui/tool-attributes/invalid-tool.rs
@@ -0,0 +1,6 @@
+#![feature(register_tool)]
+
+#![register_tool(1)]
+//~^ ERROR `register_tool` only accepts identifiers
+
+fn main() {}
diff --git a/tests/ui/tool-attributes/invalid-tool.stderr b/tests/ui/tool-attributes/invalid-tool.stderr
new file mode 100644
index 00000000000..deafa6d167c
--- /dev/null
+++ b/tests/ui/tool-attributes/invalid-tool.stderr
@@ -0,0 +1,8 @@
+error: `register_tool` only accepts identifiers
+  --> $DIR/invalid-tool.rs:3:18
+   |
+LL | #![register_tool(1)]
+   |                  ^ not an identifier
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs
index d9c422e6f70..7c9ae09349a 100644
--- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs
+++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs
@@ -1,3 +1,4 @@
+//~ ERROR overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
 //@ build-fail
 //@ compile-flags: -Zinline-mir=no
 
@@ -23,7 +24,6 @@ where
     T: Iterator<Item = ()>,
 {
     recurse(IteratorOfWrapped(elements).map(|t| t.0))
-    //~^ ERROR reached the type-length limit
 }
 
 fn main() {
diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
index c46c78609d2..c2f09371cf7 100644
--- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
+++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
@@ -1,5 +1,5 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-91949-hangs-on-recursion.rs:20:1
+  --> $DIR/issue-91949-hangs-on-recursion.rs:21:1
    |
 LL | / fn recurse<T>(elements: T) -> Vec<char>
 LL | |
@@ -13,14 +13,19 @@ LL |       recurse(IteratorOfWrapped(elements).map(|t| t.0))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error: reached the type-length limit while instantiating `<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), ...>, ...>> as Iterator>::map::<..., ...>`
-  --> $DIR/issue-91949-hangs-on-recursion.rs:25:13
+error[E0275]: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
    |
-LL |     recurse(IteratorOfWrapped(elements).map(|t| t.0))
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`)
+note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator`
+  --> $DIR/issue-91949-hangs-on-recursion.rs:14:32
    |
-   = help: consider adding a `#![type_length_limit="27262965"]` attribute to your crate
-   = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type.txt'
+LL | impl<T, I: Iterator<Item = T>> Iterator for IteratorOfWrapped<T, I> {
+   |                     --------   ^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     unsatisfied trait bound introduced here
+   = note: 256 redundant requirements hidden
+   = note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), std::iter::Empty<()>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48}>>` to implement `Iterator`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/type/ascription/issue-47666.stderr b/tests/ui/type/ascription/issue-47666.stderr
index 562ce53052b..fd825e86675 100644
--- a/tests/ui/type/ascription/issue-47666.stderr
+++ b/tests/ui/type/ascription/issue-47666.stderr
@@ -2,9 +2,13 @@ error: path separator must be a double colon
   --> $DIR/issue-47666.rs:3:19
    |
 LL |     let _ = Option:Some(vec![0, 1]);
-   |                   ^ help: use a double colon instead: `::`
+   |                   ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a double colon instead
+   |
+LL |     let _ = Option::Some(vec![0, 1]);
+   |                    +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type/ascription/issue-54516.stderr b/tests/ui/type/ascription/issue-54516.stderr
index 2c567a1a0ff..64fdc1fa24a 100644
--- a/tests/ui/type/ascription/issue-54516.stderr
+++ b/tests/ui/type/ascription/issue-54516.stderr
@@ -2,9 +2,13 @@ error: path separator must be a double colon
   --> $DIR/issue-54516.rs:5:28
    |
 LL |     println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
-   |                            ^ help: use a double colon instead: `::`
+   |                            ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a double colon instead
+   |
+LL |     println!("{}", std::mem::size_of::<BTreeMap<u32, u32>>());
+   |                             +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type/ascription/issue-60933.stderr b/tests/ui/type/ascription/issue-60933.stderr
index cd184ceba33..c68394d0504 100644
--- a/tests/ui/type/ascription/issue-60933.stderr
+++ b/tests/ui/type/ascription/issue-60933.stderr
@@ -2,9 +2,13 @@ error: path separator must be a double colon
   --> $DIR/issue-60933.rs:3:28
    |
 LL |     let _: usize = std::mem:size_of::<u32>();
-   |                            ^ help: use a double colon instead: `::`
+   |                            ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a double colon instead
+   |
+LL |     let _: usize = std::mem::size_of::<u32>();
+   |                             +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr
index 2abf27100c1..f5cf7930c83 100644
--- a/tests/ui/type/pattern_types/bad_pat.stderr
+++ b/tests/ui/type/pattern_types/bad_pat.stderr
@@ -2,17 +2,27 @@ error[E0586]: inclusive range with no end
   --> $DIR/bad_pat.rs:7:43
    |
 LL | type NonNullU32_2 = pattern_type!(u32 is 1..=);
-   |                                           ^^^ help: use `..` instead
+   |                                           ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL - type NonNullU32_2 = pattern_type!(u32 is 1..=);
+LL + type NonNullU32_2 = pattern_type!(u32 is 1..);
+   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/bad_pat.rs:9:40
    |
 LL | type Positive2 = pattern_type!(i32 is 0..=);
-   |                                        ^^^ help: use `..` instead
+   |                                        ^^^
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+help: use `..` instead
+   |
+LL - type Positive2 = pattern_type!(i32 is 0..=);
+LL + type Positive2 = pattern_type!(i32 is 0..);
+   |
 
 error: wildcard patterns are not permitted for pattern types
   --> $DIR/bad_pat.rs:11:33
diff --git a/tests/ui/type/type-ascription-instead-of-statement-end.stderr b/tests/ui/type/type-ascription-instead-of-statement-end.stderr
index 8c09e78bc5f..34c88642323 100644
--- a/tests/ui/type/type-ascription-instead-of-statement-end.stderr
+++ b/tests/ui/type/type-ascription-instead-of-statement-end.stderr
@@ -2,9 +2,13 @@ error: statements are terminated with a semicolon
   --> $DIR/type-ascription-instead-of-statement-end.rs:2:21
    |
 LL |     println!("test"):
-   |                     ^ help: use a semicolon instead: `;`
+   |                     ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a semicolon instead
+   |
+LL |     println!("test");
+   |                     ~
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
   --> $DIR/type-ascription-instead-of-statement-end.rs:7:21
diff --git a/tests/ui/type/type-ascription-with-fn-call.stderr b/tests/ui/type/type-ascription-with-fn-call.stderr
index 2ae5873c824..2691f10cf3e 100644
--- a/tests/ui/type/type-ascription-with-fn-call.stderr
+++ b/tests/ui/type/type-ascription-with-fn-call.stderr
@@ -2,9 +2,13 @@ error: statements are terminated with a semicolon
   --> $DIR/type-ascription-with-fn-call.rs:3:10
    |
 LL |     f()  :
-   |          ^ help: use a semicolon instead: `;`
+   |          ^
    |
    = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: use a semicolon instead
+   |
+LL |     f()  ;
+   |          ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type/type-dependent-def-issue-49241.stderr b/tests/ui/type/type-dependent-def-issue-49241.stderr
index 15d47cca3d2..cf372dc5968 100644
--- a/tests/ui/type/type-dependent-def-issue-49241.stderr
+++ b/tests/ui/type/type-dependent-def-issue-49241.stderr
@@ -2,9 +2,12 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/type-dependent-def-issue-49241.rs:3:22
    |
 LL |     const l: usize = v.count();
-   |     -------          ^ non-constant value
-   |     |
-   |     help: consider using `let` instead of `const`: `let l`
+   |                      ^ non-constant value
+   |
+help: consider using `let` instead of `const`
+   |
+LL |     let l: usize = v.count();
+   |     ~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type_length_limit.rs b/tests/ui/type_length_limit.rs
index d6937481a15..87f5ffd76d7 100644
--- a/tests/ui/type_length_limit.rs
+++ b/tests/ui/type_length_limit.rs
@@ -1,5 +1,5 @@
 //@ build-fail
-//@ compile-flags: -Copt-level=0
+//@ compile-flags: -Copt-level=0 -Zenforce-type-length-limit
 //~^^ ERROR reached the type-length limit
 
 // Test that the type length limit can be changed.
diff --git a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr
index 8982d628561..4450aa66c13 100644
--- a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr
+++ b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr
@@ -8,13 +8,23 @@ error: missing type for `const` item
   --> $DIR/do-not-suggest-placeholder-to-const-static-without-type.rs:2:12
    |
 LL |     const A;
-   |            ^ help: provide a type for the item: `: <type>`
+   |            ^
+   |
+help: provide a type for the item
+   |
+LL |     const A: <type>;
+   |            ++++++++
 
 error: missing type for `static` item
   --> $DIR/do-not-suggest-placeholder-to-const-static-without-type.rs:3:13
    |
 LL |     static B;
-   |             ^ help: provide a type for the item: `: <type>`
+   |             ^
+   |
+help: provide a type for the item
+   |
+LL |     static B: <type>;
+   |             ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/typeck/issue-79040.stderr b/tests/ui/typeck/issue-79040.stderr
index ce6a4b36217..39636db85a7 100644
--- a/tests/ui/typeck/issue-79040.stderr
+++ b/tests/ui/typeck/issue-79040.stderr
@@ -10,7 +10,12 @@ error: missing type for `const` item
   --> $DIR/issue-79040.rs:2:14
    |
 LL |     const FOO = "hello" + 1;
-   |              ^ help: provide a type for the item: `: <type>`
+   |              ^
+   |
+help: provide a type for the item
+   |
+LL |     const FOO: <type> = "hello" + 1;
+   |              ++++++++
 
 error[E0369]: cannot add `{integer}` to `&str`
   --> $DIR/issue-79040.rs:2:25
diff --git a/tests/ui/typeof/issue-42060.stderr b/tests/ui/typeof/issue-42060.stderr
index effcbe4d7f3..86ba9432384 100644
--- a/tests/ui/typeof/issue-42060.stderr
+++ b/tests/ui/typeof/issue-42060.stderr
@@ -1,18 +1,24 @@
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-42060.rs:3:23
    |
-LL |     let thing = ();
-   |     --------- help: consider using `const` instead of `let`: `const thing`
 LL |     let other: typeof(thing) = thing;
    |                       ^^^^^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const thing: /* Type */ = ();
+   |     ~~~~~      ++++++++++++
 
 error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/issue-42060.rs:9:13
    |
-LL |     let q = 1;
-   |     ----- help: consider using `const` instead of `let`: `const q`
 LL |     <typeof(q)>::N
    |             ^ non-constant value
+   |
+help: consider using `const` instead of `let`
+   |
+LL |     const q: /* Type */ = 1;
+   |     ~~~~~  ++++++++++++
 
 error[E0516]: `typeof` is a reserved keyword but unimplemented
   --> $DIR/issue-42060.rs:3:16
diff --git a/triagebot.toml b/triagebot.toml
index 77b3db8a010..d47d54d45c0 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -221,6 +221,13 @@ trigger_files = [
     "library/std/src/os/android"
 ]
 
+[autolabel."O-apple"]
+trigger_files = [
+    "library/std/src/os/darwin",
+    "library/std/src/sys/pal/unix/thread_parking/darwin.rs",
+    "compiler/rustc_target/src/spec/base/apple",
+]
+
 [autolabel."O-fuchsia"]
 trigger_files = [
     "library/std/src/os/fuchsia"
@@ -250,8 +257,6 @@ trigger_files = [
 [autolabel."O-macos"]
 trigger_files = [
     "library/std/src/os/macos",
-    "library/std/src/sys/pal/unix/thread_parking/darwin.rs",
-    "compiler/rustc_target/src/spec/base/apple",
 ]
 
 [autolabel."O-netbsd"]
@@ -299,22 +304,12 @@ trigger_files = [
     "library/std/src/os/wasm"
 ]
 
-[autolabel."O-watchos"]
-trigger_files = [
-    "library/std/src/os/watchos"
-]
-
 [autolabel."O-windows"]
 trigger_files = [
     "library/std/src/sys/pal/windows",
     "library/std/src/os/windows"
 ]
 
-[autolabel."O-visionos"]
-trigger_files = [
-    "library/std/src/os/visionos"
-]
-
 [autolabel."T-bootstrap"]
 trigger_files = [
     "x.py",
@@ -946,6 +941,7 @@ libs = [
     "@workingjubilee",
     "@joboet",
     "@jhpratt",
+    "@tgross35",
 ]
 bootstrap = [
     "@Mark-Simulacrum",